xref: /freebsd/share/man/man9/intr_event.9 (revision 0863dc10354ff458a3ddf8ef3b47044d7a615154)
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.Dd January 24, 2025
31.Dt INTR_EVENT 9
32.Os
33.Sh NAME
34.Nm intr_event_add_handler ,
35.Nm intr_event_create ,
36.Nm intr_event_destroy ,
37.Nm intr_event_handle ,
38.Nm intr_event_remove_handler ,
39.Nm intr_priority
40.Nd "kernel interrupt handler and thread API"
41.Sh SYNOPSIS
42.In sys/param.h
43.In sys/bus.h
44.In sys/interrupt.h
45.Ft int
46.Fo intr_event_add_handler
47.Fa "struct intr_event *ie"
48.Fa "const char *name"
49.Fa "driver_filter_t filter"
50.Fa "driver_intr_t handler"
51.Fa "void *arg"
52.Fa "u_char pri"
53.Fa "enum intr_type flags"
54.Fa "void **cookiep"
55.Fc
56.Ft int
57.Fo intr_event_create
58.Fa "struct intr_event **event"
59.Fa "void *source"
60.Fa "int flags"
61.Fa "int irq"
62.Fa "void (*pre_ithread)(void *)"
63.Fa "void (*post_ithread)(void *)"
64.Fa "void (*post_filter)(void *)"
65.Fa "int (*assign_cpu)(void *, int)"
66.Fa "const char *fmt"
67.Fa "..."
68.Fc
69.Ft int
70.Fn intr_event_destroy "struct intr_event *ie"
71.Ft int
72.Fn intr_event_handle "struct intr_event *ie" "struct trapframe *frame"
73.Ft int
74.Fn intr_event_remove_handler "void *cookie"
75.Ft u_char
76.Fn intr_priority "enum intr_type flags"
77.Sh DESCRIPTION
78The interrupt event API provides methods to manage the registration and
79execution of interrupt handlers and their associated thread contexts.
80.Pp
81Each interrupt event in the system corresponds to a single hardware or software
82interrupt source.
83Each interrupt event maintains a list of interrupt handlers, sorted by
84priority, which will be invoked when handling the event.
85An interrupt event will typically, but not always, have an associated
86.Xr kthread 9 ,
87known as the interrupt thread.
88Finally, each event contains optional callback functions which will be
89invoked before and after the handler functions themselves.
90.Pp
91An interrupt handler contains two distinct handler functions:
92the
93.Em filter
94and the thread
95.Em handler .
96The
97.Em filter
98function is run from interrupt context and is intended to perform quick
99handling such as acknowledging or masking a hardware interrupt,
100and queueing work for the ensuing thread
101.Em handler .
102Both functions are optional; each interrupt handler may choose to register a
103filter, a thread handler, or both.
104Each interrupt handler also consists of a name,
105a set of flags,
106and an opaque argument which will be passed to both the
107.Em filter
108and
109.Em handler
110functions.
111.Ss Handler Constraints
112The
113.Em filter
114function is executed inside a
115.Xr critical 9
116section.
117Therefore, filters may not yield the CPU for any reason, and may only use spin
118locks to access shared data.
119Allocating memory within a filter is not permitted.
120.Pp
121The
122.Em handler
123function executes from the context of the associated interrupt kernel thread.
124Sleeping is not permitted, but the interrupt thread may be preempted by higher
125priority threads.
126Thus, threaded handler functions may obtain non-sleepable locks, as described
127in
128.Xr locking 9 .
129Any memory or zone allocations in an interrupt thread must specify the
130.Dv M_NOWAIT
131flag, and any allocation errors must be handled.
132.Pp
133The exception to these constraints is software interrupt threads, which are
134allowed to sleep but should be allocated and scheduled using the
135.Xr swi 9
136interface.
137.Ss Function Descriptions
138The
139.Fn intr_event_create
140function creates a new interrupt event.
141The
142.Fa event
143argument points to a
144.Vt struct intr_event
145pointer that will reference the newly created event upon success.
146The
147.Fa source
148argument is an opaque pointer which will be passed to the
149.Fa pre_ithread ,
150.Fa post_ithread ,
151and
152.Fa post_filter
153callbacks.
154The
155.Fa flags
156argument is a mask of properties of this thread.
157The only valid flag currently for
158.Fn intr_event_create
159is
160.Dv IE_SOFT
161to specify that this interrupt thread is a software interrupt.
162The
163.Fa enable
164and
165.Fa disable
166arguments specify optional functions used to enable and disable this
167interrupt thread's interrupt source.
168The
169.Fa irq
170argument is the unique interrupt vector number corresponding to the event.
171The
172.Fa pre_ithread ,
173.Fa post_ithread ,
174and
175.Fa post_filter
176arguments are callback functions that are invoked at different
177points while handling an interrupt.
178This is described in more detail in the
179.Sx Handler Callbacks
180section, below.
181They may be
182.Va NULL
183to specify no callback.
184The
185.Fa assign_cpu
186argument points to a callback function that will be invoked when binding
187an interrupt to a particular CPU.
188It may be
189.Va NULL
190if binding is unsupported.
191The
192remaining arguments form a
193.Xr printf 9
194argument list that is used to build the base name of the new interrupt thread.
195The full name of an interrupt thread is formed by concatenating the base
196name of the interrupt thread with the names of all of its interrupt handlers.
197.Pp
198The
199.Fn intr_event_destroy
200function destroys a previously created interrupt event by releasing its
201resources.
202.\" The following is not true (yet):
203.\"and arranging for the backing kernel thread to terminate.
204An interrupt event can only be destroyed if it has no handlers remaining.
205.Pp
206The
207.Fn intr_event_add_handler
208function adds a new handler to an existing interrupt event specified by
209.Fa ie .
210The
211.Fa name
212argument specifies a name for this handler.
213The
214.Fa filter
215argument provide the filter function to execute.
216The
217.Fa handler
218argument provides the handler function to be executed from the
219event's interrupt thread.
220The
221.Fa arg
222argument will be passed to the
223.Fa filter
224and
225.Fa handler
226functions when they are invoked.
227The
228.Fa pri
229argument specifies the priority of this handler,
230corresponding to the values defined in
231.In sys/priority.h .
232It determines the order this handler is called relative to the other handlers
233for this event, as well as the scheduling priority of the backing kernel
234thread.
235.Fa flags
236argument can be used to specify properties of this handler as defined in
237.In sys/bus.h .
238If
239.Fa cookiep
240is not
241.Dv NULL ,
242then it will be assigned a cookie that can be used later to remove this
243handler.
244.Pp
245The
246.Fn intr_event_handle
247function is the main entry point into the interrupt handling code.
248It must be called from an interrupt context.
249The function will execute all filter handlers associated with the interrupt
250event
251.Fa ie ,
252and schedule the associated interrupt thread to run, if applicable.
253The
254.Fa frame
255argument is used to pass a pointer to the
256.Vt struct trapframe
257containing the machine state at the time of the interrupt.
258The main body of this function runs within a
259.Xr critical 9
260section.
261.Pp
262The
263.Fn intr_event_remove_handler
264function removes an interrupt handler from the interrupt event specified by
265.Fa ie .
266The
267.Fa cookie
268argument, obtained from
269.Fn intr_event_add_handler ,
270identifies the handler to remove.
271.Pp
272The
273.Fn intr_priority
274function translates the
275.Dv INTR_TYPE_*
276interrupt flags into interrupt thread scheduling priorities.
277.Pp
278The interrupt flags not related to the type of a particular interrupt
279.Pq Dv INTR_TYPE_*
280can be used to specify additional properties of both hardware and software
281interrupt handlers.
282The
283.Dv INTR_EXCL
284flag specifies that this handler cannot share an interrupt thread with
285another handler.
286The
287.Dv INTR_MPSAFE
288flag specifies that this handler is MP safe in that it does not need the
289Giant mutex to be held while it is executed.
290The
291.Dv INTR_ENTROPY
292flag specifies that the interrupt source this handler is tied to is a good
293source of entropy, and thus that entropy should be gathered when an interrupt
294from the handler's source triggers.
295Presently, the
296.Dv INTR_ENTROPY
297flag is not valid for software interrupt handlers.
298The
299.Dv INTR_SLEEPABLE
300flag specifies that the interrupt ithread may sleep.
301Presently, the
302.Dv INTR_SLEEPABLE
303flag requires the
304.Dv INTR_EXCL
305flag to be set.
306.Ss Handler Callbacks
307Each
308.Vt struct intr_event
309is assigned three optional callback functions when it is created:
310.Fa pre_ithread ,
311.Fa post_ithread ,
312and
313.Fa post_filter .
314These callbacks are intended to be defined by the interrupt controller driver,
315to allow for actions such as masking and unmasking hardware interrupt signals.
316.Pp
317When an interrupt is triggered, all filters are run to determine if any
318threaded interrupt handlers should be scheduled for execution by the associated
319interrupt thread. If no threaded handlers are scheduled, the
320.Fa post_filter
321callback is invoked which should acknowledge the interrupt and permit it to
322trigger in the future.
323If any threaded handlers are scheduled, the
324.Fa pre_ithread
325callback is invoked instead.
326This handler should acknowledge the interrupt, but it should also ensure that
327the interrupt will not fire continuously until after the threaded handlers have
328executed.
329Typically this callback masks level-triggered interrupts in an interrupt
330controller while leaving edge-triggered interrupts alone.
331Once all threaded handlers have executed,
332the
333.Fa post_ithread
334callback is invoked from the interrupt thread to enable future interrupts.
335Typically this callback unmasks level-triggered interrupts in an interrupt
336controller.
337.Sh RETURN VALUES
338The
339.Fn intr_event_add_handler ,
340.Fn intr_event_create ,
341.Fn intr_event_destroy ,
342.Fn intr_event_handle ,
343and
344.Fn intr_event_remove_handler
345functions return zero on success and non-zero on failure.
346The
347.Fn intr_priority
348function returns a process priority corresponding to the passed in interrupt
349flags.
350.Sh EXAMPLES
351The
352.Xr swi_add 9
353function demonstrates the use of
354.Fn intr_event_create
355and
356.Fn intr_event_add_handler .
357.Bd -literal -offset indent
358int
359swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler,
360    void *arg, int pri, enum intr_type flags, void **cookiep)
361{
362	struct intr_event *ie;
363	int error = 0;
364
365	if (flags & INTR_ENTROPY)
366		return (EINVAL);
367
368	ie = (eventp != NULL) ? *eventp : NULL;
369
370	if (ie != NULL) {
371		if (!(ie->ie_flags & IE_SOFT))
372			return (EINVAL);
373	} else {
374		error = intr_event_create(&ie, NULL, IE_SOFT, 0,
375		    NULL, NULL, NULL, swi_assign_cpu, "swi%d:", pri);
376		if (error)
377			return (error);
378		if (eventp != NULL)
379			*eventp = ie;
380	}
381	if (handler != NULL) {
382		error = intr_event_add_handler(ie, name, NULL, handler, arg,
383		    PI_SWI(pri), flags, cookiep);
384	}
385	return (error);
386}
387.Ed
388.Sh ERRORS
389The
390.Fn intr_event_add_handler
391function will fail if:
392.Bl -tag -width Er
393.It Bq Er EINVAL
394The
395.Fa ie
396or
397.Fa name
398arguments are
399.Dv NULL .
400.It Bq Er EINVAL
401The
402.Fa handler
403and
404.Fa filter
405arguments are both
406.Dv NULL .
407.It Bq Er EINVAL
408The
409.Dv IH_EXCLUSIVE
410flag is specified and the interrupt thread
411.Fa ie
412already has at least one handler, or the interrupt thread
413.Fa ie
414already has an exclusive handler.
415.El
416.Pp
417The
418.Fn intr_event_create
419function will fail if:
420.Bl -tag -width Er
421.It Bq Er EINVAL
422A flag other than
423.Dv IE_SOFT
424was specified in the
425.Fa flags
426parameter.
427.El
428.Pp
429The
430.Fn intr_event_destroy
431function will fail if:
432.Bl -tag -width Er
433.It Bq Er EINVAL
434The
435.Fa ie
436argument is
437.Dv NULL .
438.It Bq Er EBUSY
439The interrupt event pointed to by
440.Fa ie
441has at least one handler which has not been removed with
442.Fn intr_event_remove_handler .
443.El
444.Pp
445The
446.Fn intr_event_handle
447function will fail if:
448.Bl -tag -width Er
449.It Bq Er EINVAL
450The
451.Fa ie
452argument is
453.Dv NULL .
454.It Bq Er EINVAL
455There are no interrupt handlers assigned to
456.Fa ie .
457.It Bq Er EINVAL
458The interrupt was not acknowledged by any filter and has no associated thread
459handler.
460.El
461.Pp
462The
463.Fn intr_event_remove_handler
464function will fail if:
465.Bl -tag -width Er
466.It Bq Er EINVAL
467The
468.Fa cookie
469argument is
470.Dv NULL .
471.El
472.Sh SEE ALSO
473.Xr critical 9 ,
474.Xr kthread 9 ,
475.Xr locking 9 ,
476.Xr malloc 9 ,
477.Xr swi 9 ,
478.Xr uma 9
479.Sh HISTORY
480Interrupt threads and their corresponding API first appeared in
481.Fx 5.0 .
482