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