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