Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Jul 2004 14:08:54 -0400
From:      Brian Fundakowski Feldman <green@FreeBSD.org>
To:        current@FreeBSD.org
Subject:   pccbb crashes when detaching (unsafe interrupt handler)
Message-ID:  <20040715180854.GZ1626@green.homeunix.org>

next in thread | raw e-mail | index | archive | help
Devices that attach to a pccbb end up getting screwed if they share
interrupt handlers with anything else and one comes in at such time
that the interrupt handler has been deallocated but not torn down.
There is no interrupt protection for the pccbb interrupt handler,
and the cleanest method I can think of is add a "don't run" count to
the real ithread interrupt handler (parent); however, this is a fair
bit of infrastructure if it's not something very useful, and in SMP,
concurrent accesses of the local interrupt handler list in pccbb do
need to be protected, not just preventing interrupt handlers.

This is what I have so far, but I'm not happy with it because it
seems like it would be so much nicer to increment a count on the
ithread's intrhand and drain any current interrupt out of the
ithread, but possibly making each interrupt a lot more expensive.

Index: pccbb.c
===================================================================
RCS file: /usr/ncvs/src/sys/dev/pccbb/pccbb.c,v
retrieving revision 1.114
diff -u -r1.114 pccbb.c
--- pccbb.c	23 Jun 2004 13:49:46 -0000	1.114
+++ pccbb.c	14 Jul 2004 21:59:49 -0000
@@ -85,6 +85,7 @@
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
+#include <sys/sx.h>
 #include <sys/sysctl.h>
 #include <sys/kthread.h>
 #include <sys/bus.h>
@@ -696,6 +697,7 @@
 	parent = device_get_parent(brdev);
 	mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF);
 	cv_init(&sc->cv, "cbb cv");
+	sx_init(&sc->intrsx, "cbb intr sx");
 	sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL);
 	sc->dev = brdev;
 	sc->cbdev = NULL;
@@ -715,6 +717,7 @@
 		device_printf(brdev, "Could not map register memory\n");
 		mtx_destroy(&sc->mtx);
 		cv_destroy(&sc->cv);
+		sx_destroy(&sc->intrsx);
 		return (ENOMEM);
 	} else {
 		DEVPRINTF((brdev, "Found memory at %08lx\n",
@@ -813,6 +816,7 @@
 	}
 	mtx_destroy(&sc->mtx);
 	cv_destroy(&sc->cv);
+	sx_destroy(&sc->intrsx);
 	return (ENOMEM);
 }
 
@@ -852,6 +856,7 @@
 	    sc->base_res);
 	mtx_destroy(&sc->mtx);
 	cv_destroy(&sc->cv);
+	sx_destroy(&sc->intrsx);
 	return (0);
 }
 
@@ -903,7 +908,9 @@
 	ih->intr = intr;
 	ih->arg = arg;
 	ih->flags = flags & INTR_MPSAFE;
+	sx_xlock(&sc->intrsx);
 	STAILQ_INSERT_TAIL(&sc->intr_handlers, ih, entries);
+	sx_xunlock(&sc->intrsx);
 	cbb_enable_func_intr(sc);
 	/*
 	 * XXX need to turn on ISA interrupts, if we ever support them, but
@@ -921,7 +928,9 @@
 
 	/* XXX Need to do different things for ISA interrupts. */
 	ih = (struct cbb_intrhand *) cookie;
+	sx_xlock(&sc->intrsx);
 	STAILQ_REMOVE(&sc->intr_handlers, ih, cbb_intrhand, entries);
+	sx_xunlock(&sc->intrsx);
 	free(ih, M_DEVBUF);
 	return (0);
 }
@@ -1147,13 +1156,28 @@
 	 * If the card is OK, call all the interrupt handlers.
  	 */
 	if (sc->flags & CBB_CARD_OK) {
+		int needgiant = 0;
+
+		sx_slock(&sc->intrsx);
 		STAILQ_FOREACH(ih, &sc->intr_handlers, entries) {
-			if ((ih->flags & INTR_MPSAFE) == 0)
-				mtx_lock(&Giant);
-			(*ih->intr)(ih->arg);
-			if ((ih->flags & INTR_MPSAFE) == 0)
-				mtx_unlock(&Giant);
+			if ((ih->flags & INTR_MPSAFE) == 0) {
+				needgiant = 1;
+				break;
+			}
+		}
+		if (!needgiant) {
+			STAILQ_FOREACH(ih, &sc->intr_handlers, entries)
+				(*ih->intr)(ih->arg);
+			sx_sunlock(&sc->intrsx);
+			return;
 		}
+		sx_sunlock(&sc->intrsx);
+		mtx_lock(&Giant);
+		sx_slock(&sc->intrsx);
+		STAILQ_FOREACH(ih, &sc->intr_handlers, entries)
+			(*ih->intr)(ih->arg);
+		sx_sunlock(&sc->intrsx);
+		mtx_unlock(&Giant);
 	}
 }
 
Index: pccbbvar.h
===================================================================
RCS file: /usr/ncvs/src/sys/dev/pccbb/pccbbvar.h,v
retrieving revision 1.20
diff -u -r1.20 pccbbvar.h
--- pccbbvar.h	21 May 2004 06:10:13 -0000	1.20
+++ pccbbvar.h	14 Jul 2004 21:58:22 -0000
@@ -65,6 +65,7 @@
 	u_int8_t	subbus;
 	struct mtx	mtx;
 	struct cv	cv;
+	struct sx	intrsx;
 	u_int32_t	flags;
 #define CBB_CARD_OK		0x08000000
 #define	CBB_16BIT_CARD		0x20000000


-- 
Brian Fundakowski Feldman                           \'[ FreeBSD ]''''''''''\
  <> green@FreeBSD.org                               \  The Power to Serve! \
 Opinions expressed are my own.                       \,,,,,,,,,,,,,,,,,,,,,,\



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040715180854.GZ1626>