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