git: 28137bdb19aa - main - intrng: track counter allocation with a bitmap

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Tue, 14 Feb 2023 18:23:54 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=28137bdb19aa34b8351108de4257795a93c0ba09

commit 28137bdb19aa34b8351108de4257795a93c0ba09
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2023-02-14 18:02:12 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-02-14 18:06:00 +0000

    intrng: track counter allocation with a bitmap
    
    Crucially, this allows releasing counters, and interrupt sources by
    extension. Where before we were incrementing intrcnt_index with atomics,
    now we protect the bitmap using the existing isrc_table_lock mutex.
    
    Reviewed by:    mmel
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D38437
---
 sys/kern/subr_intr.c | 54 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 40 insertions(+), 14 deletions(-)

diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
index 96a319b3c8b4..a95d2adbed04 100644
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/bitstring.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/cpuset.h>
@@ -152,7 +153,8 @@ u_long *intrcnt;
 char *intrnames;
 size_t sintrcnt;
 size_t sintrnames;
-static u_int intrcnt_index;
+int nintrcnt;
+static bitstr_t *intrcnt_bitmap;
 
 static struct intr_irqsrc *intr_map_get_isrc(u_int res_id);
 static void intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc);
@@ -166,7 +168,6 @@ static void intr_map_copy_map_data(u_int res_id, device_t *dev, intptr_t *xref,
 static void
 intr_irq_init(void *dummy __unused)
 {
-	u_int intrcnt_count;
 
 	SLIST_INIT(&pic_list);
 	mtx_init(&pic_list_lock, "intr pic list", NULL, MTX_DEF);
@@ -177,17 +178,21 @@ intr_irq_init(void *dummy __unused)
 	 * - 2 counters for each I/O interrupt.
 	 * - MAXCPU counters for each IPI counters for SMP.
 	 */
-	intrcnt_count = intr_nirq * 2;
+	nintrcnt = intr_nirq * 2;
 #ifdef SMP
-	intrcnt_count += INTR_IPI_COUNT * MAXCPU;
+	nintrcnt += INTR_IPI_COUNT * MAXCPU;
 #endif
 
-	intrcnt = mallocarray(intrcnt_count, sizeof(u_long), M_INTRNG,
+	intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTRNG,
 	    M_WAITOK | M_ZERO);
-	intrnames = mallocarray(intrcnt_count, INTRNAME_LEN, M_INTRNG,
+	intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTRNG,
 	    M_WAITOK | M_ZERO);
-	sintrcnt = intrcnt_count * sizeof(u_long);
-	sintrnames = intrcnt_count * INTRNAME_LEN;
+	sintrcnt = nintrcnt * sizeof(u_long);
+	sintrnames = nintrcnt * INTRNAME_LEN;
+
+	/* Allocate the bitmap tracking counter allocations. */
+	intrcnt_bitmap = bit_alloc(nintrcnt, M_INTRNG, M_WAITOK | M_ZERO);
+
 	irq_sources = mallocarray(intr_nirq, sizeof(struct intr_irqsrc*),
 	    M_INTRNG, M_WAITOK | M_ZERO);
 }
@@ -266,13 +271,17 @@ isrc_update_name(struct intr_irqsrc *isrc, const char *name)
 static void
 isrc_setup_counters(struct intr_irqsrc *isrc)
 {
-	u_int index;
+	int index;
+
+	mtx_assert(&isrc_table_lock, MA_OWNED);
 
 	/*
-	 *  XXX - it does not work well with removable controllers and
-	 *        interrupt sources !!!
+	 * Allocate two counter values, the second tracking "stray" interrupts.
 	 */
-	index = atomic_fetchadd_int(&intrcnt_index, 2);
+	bit_ffc_area(intrcnt_bitmap, nintrcnt, 2, &index);
+	if (index == -1)
+		panic("Failed to allocate 2 counters. Array exhausted?");
+	bit_nset(intrcnt_bitmap, index, index + 1);
 	isrc->isrc_index = index;
 	isrc->isrc_count = &intrcnt[index];
 	isrc_update_name(isrc, NULL);
@@ -284,8 +293,11 @@ isrc_setup_counters(struct intr_irqsrc *isrc)
 static void
 isrc_release_counters(struct intr_irqsrc *isrc)
 {
+	int idx = isrc->isrc_index;
 
-	panic("%s: not implemented", __func__);
+	mtx_assert(&isrc_table_lock, MA_OWNED);
+
+	bit_nclear(intrcnt_bitmap, idx, idx + 1);
 }
 
 #ifdef SMP
@@ -298,11 +310,25 @@ intr_ipi_setup_counters(const char *name)
 	u_int index, i;
 	char str[INTRNAME_LEN];
 
-	index = atomic_fetchadd_int(&intrcnt_index, MAXCPU);
+	mtx_lock(&isrc_table_lock);
+
+	/*
+	 * We should never have a problem finding MAXCPU contiguous counters,
+	 * in practice. Interrupts will be allocated sequentially during boot,
+	 * so the array should fill from low to high index. Once reserved, the
+	 * IPI counters will never be released. Similarly, we will not need to
+	 * allocate more IPIs once the system is running.
+	 */
+	bit_ffc_area(intrcnt_bitmap, nintrcnt, MAXCPU, &index);
+	if (index == -1)
+		panic("Failed to allocate %d counters. Array exhausted?",
+		    MAXCPU);
+	bit_nset(intrcnt_bitmap, index, index + MAXCPU - 1);
 	for (i = 0; i < MAXCPU; i++) {
 		snprintf(str, INTRNAME_LEN, "cpu%d:%s", i, name);
 		intrcnt_setname(str, index + i);
 	}
+	mtx_unlock(&isrc_table_lock);
 	return (&intrcnt[index]);
 }
 #endif