diff --git a/share/man/man9/swi.9 b/share/man/man9/swi.9 index 52a39fe61c86..d86538e31fd1 100644 --- a/share/man/man9/swi.9 +++ b/share/man/man9/swi.9 @@ -1,256 +1,251 @@ .\" Copyright (c) 2000-2001 John H. Baldwin .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd July 25, 2020 .Dt SWI 9 .Os .Sh NAME .Nm swi_add , .Nm swi_remove , .Nm swi_sched .Nd register and schedule software interrupt handlers .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .In sys/interrupt.h .Vt "extern struct intr_event *tty_intr_event" ; .Vt "extern struct intr_event *clk_intr_event" ; -.Vt "extern void *vm_ih" ; .Ft int .Fo swi_add .Fa "struct intr_event **eventp" .Fa "const char *name" .Fa "driver_intr_t handler" .Fa "void *arg" .Fa "int pri" .Fa "enum intr_type flags" .Fa "void **cookiep" .Fc .Ft int .Fn swi_remove "void *cookie" .Ft void .Fn swi_sched "void *cookie" "int flags" .Sh DESCRIPTION These functions are used to register and schedule software interrupt handlers. Software interrupt handlers are attached to a software interrupt thread, just as hardware interrupt handlers are attached to a hardware interrupt thread. Multiple handlers can be attached to the same thread. Software interrupt handlers can be used to queue up less critical processing inside of hardware interrupt handlers so that the work can be done at a later time. Software interrupt threads are different from other kernel threads in that they are treated as an interrupt thread. This means that time spent executing these threads is counted as interrupt time, and that they can be run via a lightweight context switch. .Pp The .Fn swi_add function is used to add a new software interrupt handler to a specified interrupt event. The .Fa eventp argument is an optional pointer to a .Vt struct intr_event pointer. If this argument points to an existing event that holds a list of interrupt handlers, then this handler will be attached to that event. Otherwise a new event will be created, and if .Fa eventp is not .Dv NULL , then the pointer at that address to will be modified to point to the newly created event. The .Fa name argument is used to associate a name with a specific handler. This name is appended to the name of the software interrupt thread that this handler is attached to. The .Fa handler argument is the function that will be executed when the handler is scheduled to run. The .Fa arg parameter will be passed in as the only parameter to .Fa handler when the function is executed. The .Fa pri value specifies the priority of this interrupt handler relative to other software interrupt handlers. If an interrupt event is created, then this value is used as the vector, and the .Fa flags argument is used to specify the attributes of a handler such as .Dv INTR_MPSAFE . The .Fa cookiep argument points to a .Vt void * cookie. This cookie will be set to a value that uniquely identifies this handler, and is used to schedule the handler for execution later on. .Pp The .Fn swi_remove function is used to teardown an interrupt handler pointed to by the .Fa cookie argument. It detaches the interrupt handler from the associated interrupt event and frees its memory. .Pp The .Fn swi_sched function is used to schedule an interrupt handler and its associated thread to run. The .Fa cookie argument specifies which software interrupt handler should be scheduled to run. The .Fa flags argument specifies how and when the handler should be run and is a mask of one or more of the following flags: .Bl -tag -width SWI_FROMNMI .It Dv SWI_DELAY Specifies that the kernel should mark the specified handler as needing to run, but the kernel should not schedule the software interrupt thread to run. Instead, .Fa handler will be executed the next time that the software interrupt thread runs after being scheduled by another event. Attaching a handler to the clock software interrupt thread and using this flag when scheduling a software interrupt handler can be used to implement the functionality performed by .Fn setdelayed in earlier versions of .Fx . .It Dv SWI_FROMNMI Specifies that .Fn swi_sched is called from NMI context and should be careful about used KPIs. On platforms allowing IPI sending from NMI context it immediately wakes .Va clk_intr_event via the IPI, otherwise it works just like SWI_DELAY. .El .Pp The .Va tty_intr_event and .Va clk_intr_event variables contain pointers to the software interrupt handlers for the tty and clock software interrupts, respectively. .Va tty_intr_event is used to hang tty software interrupt handlers off of the same thread. .Va clk_intr_event is used to hang delayed handlers off of the clock software interrupt thread so that the functionality of .Fn setdelayed can be obtained in conjunction with .Dv SWI_DELAY . -The -.Va vm_ih -handler cookie is used to schedule software interrupt threads to run for the -VM subsystem. .Sh RETURN VALUES The .Fn swi_add and .Fn swi_remove functions return zero on success and non-zero on failure. .Sh ERRORS The .Fn swi_add function will fail if: .Bl -tag -width Er .It Bq Er EAGAIN The system-imposed limit on the total number of processes under execution would be exceeded. The limit is given by the .Xr sysctl 3 MIB variable .Dv KERN_MAXPROC . .It Bq Er EINVAL The .Fa flags argument specifies .Dv INTR_ENTROPY . .It Bq Er EINVAL The .Fa eventp argument points to a hardware interrupt thread. .It Bq Er EINVAL Either of the .Fa name or .Fa handler arguments are .Dv NULL . .It Bq Er EINVAL The .Dv INTR_EXCL flag is specified and the interrupt event pointed to by .Fa eventp already has at least one handler, or the interrupt event already has an exclusive handler. .El .Pp The .Fn swi_remove function will fail if: .Bl -tag -width Er .It Bq Er EINVAL A software interrupt handler pointed to by .Fa cookie is .Dv NULL . .El .Sh SEE ALSO .Xr ithread 9 , .Xr taskqueue 9 .Sh HISTORY The .Fn swi_add and .Fn swi_sched functions first appeared in .Fx 5.0 . They replaced the .Fn register_swi function which appeared in .Fx 3.0 and the .Fn setsoft* , and .Fn schedsoft* functions which date back to at least .Bx 4.4 . The .Fn swi_remove function first appeared in .Fx 6.1 . .Sh BUGS Most of the global variables described in this manual page should not be global, or at the very least should not be declared in .In sys/interrupt.h . diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h index 09162469daed..f099e73e80d9 100644 --- a/sys/sys/interrupt.h +++ b/sys/sys/interrupt.h @@ -1,200 +1,199 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 1997, Stefan Esser * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_INTERRUPT_H_ #define _SYS_INTERRUPT_H_ #include #include #include struct intr_event; struct intr_thread; struct trapframe; /* * Describe a hardware interrupt handler. * * Multiple interrupt handlers for a specific event can be chained * together. */ struct intr_handler { driver_filter_t *ih_filter; /* Filter handler function. */ driver_intr_t *ih_handler; /* Threaded handler function. */ void *ih_argument; /* Argument to pass to handlers. */ int ih_flags; char ih_name[MAXCOMLEN + 1]; /* Name of handler. */ struct intr_event *ih_event; /* Event we are connected to. */ int ih_need; /* Needs service. */ CK_SLIST_ENTRY(intr_handler) ih_next; /* Next handler for this event. */ u_char ih_pri; /* Priority of this handler. */ }; /* Interrupt handle flags kept in ih_flags */ #define IH_NET 0x00000001 /* Network. */ #define IH_EXCLUSIVE 0x00000002 /* Exclusive interrupt. */ #define IH_ENTROPY 0x00000004 /* Device is a good entropy source. */ #define IH_DEAD 0x00000008 /* Handler should be removed. */ #define IH_SUSP 0x00000010 /* Device is powered down. */ #define IH_CHANGED 0x40000000 /* Handler state is changed. */ #define IH_MPSAFE 0x80000000 /* Handler does not need Giant. */ /* * Describe an interrupt event. An event holds a list of handlers. * The 'pre_ithread', 'post_ithread', 'post_filter', and 'assign_cpu' * hooks are used to invoke MD code for certain operations. * * The 'pre_ithread' hook is called when an interrupt thread for * handlers without filters is scheduled. It is responsible for * ensuring that 1) the system won't be swamped with an interrupt * storm from the associated source while the ithread runs and 2) the * current CPU is able to receive interrupts from other interrupt * sources. The first is usually accomplished by disabling * level-triggered interrupts until the ithread completes. The second * is accomplished on some platforms by acknowledging the interrupt * via an EOI. * * The 'post_ithread' hook is invoked when an ithread finishes. It is * responsible for ensuring that the associated interrupt source will * trigger an interrupt when it is asserted in the future. Usually * this is implemented by enabling a level-triggered interrupt that * was previously disabled via the 'pre_ithread' hook. * * The 'post_filter' hook is invoked when a filter handles an * interrupt. It is responsible for ensuring that the current CPU is * able to receive interrupts again. On some platforms this is done * by acknowledging the interrupts via an EOI. * * The 'assign_cpu' hook is used to bind an interrupt source to a * specific CPU. If the interrupt cannot be bound, this function may * return an error. * * Note that device drivers may also use interrupt events to manage * multiplexing interrupt interrupt handler into handlers for child * devices. In that case, the above hooks are not used. The device * can create an event for its interrupt resource and register child * event handlers with that event. It can then use * intr_event_execute_handlers() to execute non-filter handlers. * Currently filter handlers are not supported by this, but that can * be added by splitting out the filter loop from intr_event_handle() * if desired. */ struct intr_event { TAILQ_ENTRY(intr_event) ie_list; CK_SLIST_HEAD(, intr_handler) ie_handlers; /* Interrupt handlers. */ char ie_name[MAXCOMLEN + 1]; /* Individual event name. */ char ie_fullname[MAXCOMLEN + 1]; struct mtx ie_lock; void *ie_source; /* Cookie used by MD code. */ struct intr_thread *ie_thread; /* Thread we are connected to. */ void (*ie_pre_ithread)(void *); void (*ie_post_ithread)(void *); void (*ie_post_filter)(void *); int (*ie_assign_cpu)(void *, int); int ie_flags; int ie_hflags; /* Cumulative flags of all handlers. */ int ie_count; /* Loop counter. */ int ie_warncnt; /* Rate-check interrupt storm warns. */ struct timeval ie_warntm; int ie_irq; /* Physical irq number if !SOFT. */ int ie_cpu; /* CPU this event is bound to. */ volatile int ie_phase; /* Switched to establish a barrier. */ volatile int ie_active[2]; /* Filters in ISR context. */ }; /* Interrupt event flags kept in ie_flags. */ #define IE_SOFT 0x000001 /* Software interrupt. */ #define IE_ADDING_THREAD 0x000004 /* Currently building an ithread. */ /* Flags to pass to swi_sched. */ #define SWI_FROMNMI 0x1 #define SWI_DELAY 0x2 /* * Software interrupt numbers in priority order. The priority determines * the priority of the corresponding interrupt thread. */ #define SWI_TTY 0 #define SWI_NET 1 #define SWI_CAMBIO 2 #define SWI_BUSDMA 3 #define SWI_CLOCK 4 #define SWI_TQ_FAST 5 #define SWI_TQ 6 #define SWI_TQ_GIANT 6 struct proc; extern struct intr_event *clk_intr_event; extern struct intr_event *tty_intr_event; -extern void *vm_ih; /* Counts and names for statistics (defined in MD code). */ extern u_long *intrcnt; /* counts for each device and stray */ extern char *intrnames; /* string table containing device names */ extern size_t sintrcnt; /* size of intrcnt table */ extern size_t sintrnames; /* size of intrnames table */ #ifdef DDB void db_dump_intr_event(struct intr_event *ie, int handlers); #endif u_char intr_priority(enum intr_type flags); int intr_event_add_handler(struct intr_event *ie, const char *name, driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, void **cookiep); int intr_event_bind(struct intr_event *ie, int cpu); int intr_event_bind_irqonly(struct intr_event *ie, int cpu); int intr_event_bind_ithread(struct intr_event *ie, int cpu); struct _cpuset; int intr_event_bind_ithread_cpuset(struct intr_event *ie, struct _cpuset *mask); int intr_event_create(struct intr_event **event, void *source, int flags, int irq, void (*pre_ithread)(void *), void (*post_ithread)(void *), void (*post_filter)(void *), int (*assign_cpu)(void *, int), const char *fmt, ...) __printflike(9, 10); int intr_event_describe_handler(struct intr_event *ie, void *cookie, const char *descr); int intr_event_destroy(struct intr_event *ie); int intr_event_handle(struct intr_event *ie, struct trapframe *frame); int intr_event_remove_handler(void *cookie); int intr_event_suspend_handler(void *cookie); int intr_event_resume_handler(void *cookie); int intr_getaffinity(int irq, int mode, void *mask); void *intr_handler_source(void *cookie); int intr_setaffinity(int irq, int mode, void *mask); void _intr_drain(int irq); /* LinuxKPI only. */ int swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, void *arg, int pri, enum intr_type flags, void **cookiep); void swi_sched(void *cookie, int flags); int swi_remove(void *cookie); #endif