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