The branch main has been updated by andrew:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=0863dc10354ff458a3ddf8ef3b47044d7a615154

commit 0863dc10354ff458a3ddf8ef3b47044d7a615154
Author:     Andrew Turner <and...@freebsd.org>
AuthorDate: 2025-01-13 05:35:27 +0000
Commit:     Andrew Turner <and...@freebsd.org>
CommitDate: 2025-01-24 15:08:09 +0000

    ithread: Allow some ithreads to sleep
    
    Some ithreads need to hold a sleep mutex, e.g. when calling ACPI
    methods. Allow ithreads to be marked as sleepable when this is known
    to be safe.
    
    Reviewed by:    markj, jhb
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D48283
---
 share/man/man9/intr_event.9 | 10 +++++++++-
 sys/kern/kern_intr.c        | 18 +++++++++++++-----
 sys/sys/bus.h               |  1 +
 sys/sys/interrupt.h         |  1 +
 4 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/share/man/man9/intr_event.9 b/share/man/man9/intr_event.9
index d1964ce289a5..ba8faf877e6a 100644
--- a/share/man/man9/intr_event.9
+++ b/share/man/man9/intr_event.9
@@ -27,7 +27,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd October 30, 2022
+.Dd January 24, 2025
 .Dt INTR_EVENT 9
 .Os
 .Sh NAME
@@ -295,6 +295,14 @@ from the handler's source triggers.
 Presently, the
 .Dv INTR_ENTROPY
 flag is not valid for software interrupt handlers.
+The
+.Dv INTR_SLEEPABLE
+flag specifies that the interrupt ithread may sleep.
+Presently, the
+.Dv INTR_SLEEPABLE
+flag requires the
+.Dv INTR_EXCL
+flag to be set.
 .Ss Handler Callbacks
 Each
 .Vt struct intr_event
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
index ad0cc135167e..4ef37ac829b3 100644
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -610,6 +610,12 @@ intr_event_add_handler(struct intr_event *ie, const char 
*name,
        if (ie == NULL || name == NULL || (handler == NULL && filter == NULL))
                return (EINVAL);
 
+       if ((flags & INTR_SLEEPABLE) != 0 && (flags & INTR_EXCL) == 0) {
+               printf("%s: INTR_SLEEPABLE requires INTR_EXCL to be set\n",
+                   __func__);
+               return (EINVAL);
+       }
+
        /* Allocate and populate an interrupt handler structure. */
        ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO);
        ih->ih_filter = filter;
@@ -627,16 +633,18 @@ intr_event_add_handler(struct intr_event *ie, const char 
*name,
        if (flags & INTR_TYPE_NET)
                ih->ih_flags |= IH_NET;
 
-       /* We can only have one exclusive handler in a event. */
+       /* We can only have one exclusive or sleepable handler in a event. */
        mtx_lock(&ie->ie_lock);
        if (!CK_SLIST_EMPTY(&ie->ie_handlers)) {
-               if ((flags & INTR_EXCL) ||
+               if ((flags & (INTR_EXCL | INTR_SLEEPABLE)) ||
                    (CK_SLIST_FIRST(&ie->ie_handlers)->ih_flags & 
IH_EXCLUSIVE)) {
                        mtx_unlock(&ie->ie_lock);
                        free(ih, M_ITHREAD);
                        return (EINVAL);
                }
        }
+       if (flags & INTR_SLEEPABLE)
+               ie->ie_flags |= IE_SLEEPABLE;
 
        /* Create a thread if we need one. */
        while (ie->ie_thread == NULL && handler != NULL) {
@@ -1190,11 +1198,11 @@ static void
 ithread_execute_handlers(struct proc *p, struct intr_event *ie)
 {
 
-       /* Interrupt handlers should not sleep. */
-       if (!(ie->ie_flags & IE_SOFT))
+       /* Only specifically marked sleepable interrupt handlers can sleep. */
+       if (!(ie->ie_flags & (IE_SOFT | IE_SLEEPABLE)))
                THREAD_NO_SLEEPING();
        intr_event_execute_handlers(p, ie);
-       if (!(ie->ie_flags & IE_SOFT))
+       if (!(ie->ie_flags & (IE_SOFT | IE_SLEEPABLE)))
                THREAD_SLEEPING_OK();
 
        /*
diff --git a/sys/sys/bus.h b/sys/sys/bus.h
index 8b32e10f1285..84df9e6956d3 100644
--- a/sys/sys/bus.h
+++ b/sys/sys/bus.h
@@ -277,6 +277,7 @@ enum intr_type {
        INTR_EXCL = 256,                /* exclusive interrupt */
        INTR_MPSAFE = 512,              /* this interrupt is SMP safe */
        INTR_ENTROPY = 1024,            /* this interrupt provides entropy */
+       INTR_SLEEPABLE = 2048,          /* this interrupt handler can sleep */
        INTR_MD1 = 4096,                /* flag reserved for MD use */
        INTR_MD2 = 8192,                /* flag reserved for MD use */
        INTR_MD3 = 16384,               /* flag reserved for MD use */
diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h
index 899d65e386e0..2e84faa78e38 100644
--- a/sys/sys/interrupt.h
+++ b/sys/sys/interrupt.h
@@ -129,6 +129,7 @@ struct intr_event {
 
 /* Interrupt event flags kept in ie_flags. */
 #define        IE_SOFT         0x000001        /* Software interrupt. */
+#define        IE_SLEEPABLE    0x000002        /* Sleepable ithread */
 #define        IE_ADDING_THREAD 0x000004       /* Currently building an 
ithread. */
 
 /* Flags to pass to swi_sched. */

Reply via email to