xref: /freebsd/share/man/man9/intr_event.9 (revision fa9896e082a1046ff4fbc75fcba4d18d1f2efc19)
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 October 30, 2022
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 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.
298.Ss Handler Callbacks
299Each
300.Vt struct intr_event
301is assigned three optional callback functions when it is created:
302.Fa pre_ithread ,
303.Fa post_ithread ,
304and
305.Fa post_filter .
306These callbacks are intended to be defined by the interrupt controller driver,
307to allow for actions such as masking and unmasking hardware interrupt signals.
308.Pp
309When an interrupt is triggered, all filters are run to determine if any
310threaded interrupt handlers should be scheduled for execution by the associated
311interrupt thread. If no threaded handlers are scheduled, the
312.Fa post_filter
313callback is invoked which should acknowledge the interrupt and permit it to
314trigger in the future.
315If any threaded handlers are scheduled, the
316.Fa pre_ithread
317callback is invoked instead.
318This handler should acknowledge the interrupt, but it should also ensure that
319the interrupt will not fire continuously until after the threaded handlers have
320executed.
321Typically this callback masks level-triggered interrupts in an interrupt
322controller while leaving edge-triggered interrupts alone.
323Once all threaded handlers have executed,
324the
325.Fa post_ithread
326callback is invoked from the interrupt thread to enable future interrupts.
327Typically this callback unmasks level-triggered interrupts in an interrupt
328controller.
329.Sh RETURN VALUES
330The
331.Fn intr_event_add_handler ,
332.Fn intr_event_create ,
333.Fn intr_event_destroy ,
334.Fn intr_event_handle ,
335and
336.Fn intr_event_remove_handler
337functions return zero on success and non-zero on failure.
338The
339.Fn intr_priority
340function returns a process priority corresponding to the passed in interrupt
341flags.
342.Sh EXAMPLES
343The
344.Xr swi_add 9
345function demonstrates the use of
346.Fn intr_event_create
347and
348.Fn intr_event_add_handler .
349.Bd -literal -offset indent
350int
351swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler,
352    void *arg, int pri, enum intr_type flags, void **cookiep)
353{
354	struct intr_event *ie;
355	int error = 0;
356
357	if (flags & INTR_ENTROPY)
358		return (EINVAL);
359
360	ie = (eventp != NULL) ? *eventp : NULL;
361
362	if (ie != NULL) {
363		if (!(ie->ie_flags & IE_SOFT))
364			return (EINVAL);
365	} else {
366		error = intr_event_create(&ie, NULL, IE_SOFT, 0,
367		    NULL, NULL, NULL, swi_assign_cpu, "swi%d:", pri);
368		if (error)
369			return (error);
370		if (eventp != NULL)
371			*eventp = ie;
372	}
373	if (handler != NULL) {
374		error = intr_event_add_handler(ie, name, NULL, handler, arg,
375		    PI_SWI(pri), flags, cookiep);
376	}
377	return (error);
378}
379.Ed
380.Sh ERRORS
381The
382.Fn intr_event_add_handler
383function will fail if:
384.Bl -tag -width Er
385.It Bq Er EINVAL
386The
387.Fa ie
388or
389.Fa name
390arguments are
391.Dv NULL .
392.It Bq Er EINVAL
393The
394.Fa handler
395and
396.Fa filter
397arguments are both
398.Dv NULL .
399.It Bq Er EINVAL
400The
401.Dv IH_EXCLUSIVE
402flag is specified and the interrupt thread
403.Fa ie
404already has at least one handler, or the interrupt thread
405.Fa ie
406already has an exclusive handler.
407.El
408.Pp
409The
410.Fn intr_event_create
411function will fail if:
412.Bl -tag -width Er
413.It Bq Er EINVAL
414A flag other than
415.Dv IE_SOFT
416was specified in the
417.Fa flags
418parameter.
419.El
420.Pp
421The
422.Fn intr_event_destroy
423function will fail if:
424.Bl -tag -width Er
425.It Bq Er EINVAL
426The
427.Fa ie
428argument is
429.Dv NULL .
430.It Bq Er EBUSY
431The interrupt event pointed to by
432.Fa ie
433has at least one handler which has not been removed with
434.Fn intr_event_remove_handler .
435.El
436.Pp
437The
438.Fn intr_event_handle
439function will fail if:
440.Bl -tag -width Er
441.It Bq Er EINVAL
442The
443.Fa ie
444argument is
445.Dv NULL .
446.It Bq Er EINVAL
447There are no interrupt handlers assigned to
448.Fa ie .
449.It Bq Er EINVAL
450The interrupt was not acknowledged by any filter and has no associated thread
451handler.
452.El
453.Pp
454The
455.Fn intr_event_remove_handler
456function will fail if:
457.Bl -tag -width Er
458.It Bq Er EINVAL
459The
460.Fa cookie
461argument is
462.Dv NULL .
463.El
464.Sh SEE ALSO
465.Xr critical 9 ,
466.Xr kthread 9 ,
467.Xr locking 9 ,
468.Xr malloc 9 ,
469.Xr swi 9 ,
470.Xr uma 9
471.Sh HISTORY
472Interrupt threads and their corresponding API first appeared in
473.Fx 5.0 .
474