git: 0863dc10354f - main - ithread: Allow some ithreads to sleep

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Fri, 24 Jan 2025 15:08:25 UTC
The branch main has been updated by andrew:

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

commit 0863dc10354ff458a3ddf8ef3b47044d7a615154
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-01-13 05:35:27 +0000
Commit:     Andrew Turner <andrew@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. */