summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/os/softint.c82
-rw-r--r--usr/src/uts/sun4/os/ddi_impl.c3
-rw-r--r--usr/src/uts/sun4/os/intr.c32
3 files changed, 97 insertions, 20 deletions
diff --git a/usr/src/uts/common/os/softint.c b/usr/src/uts/common/os/softint.c
index 9d3587b35b..8169082adf 100644
--- a/usr/src/uts/common/os/softint.c
+++ b/usr/src/uts/common/os/softint.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,9 +37,33 @@
/*
* Handle software interrupts through 'softcall' mechanism
+ *
+ * At present softcall mechanism uses a global list headed by softhead.
+ * Entries are added to tail and removed from head so as to preserve FIFO
+ * nature of entries in the softcall list. softcall() takes care of adding
+ * entries to the softtail.
+ *
+ * softint must take care of executing the entries in the FIFO
+ * order. It could be called simultaneously from multiple cpus, however only
+ * one instance of softint should process the softcall list, this is
+ * ensured by
+ * - the state the variable softcall_state will be at time to time.
+ * (IDLE->PEND->DRAIN->IDLE)
+ *
+ * These states are needed for softcall mechanism since Solaris has only
+ * one interface(ie. siron ) as of now for
+ * - raising a soft interrupt architecture independently(ie not through
+ * setsoftint(..) )
+ * - to process the softcall queue.
*/
#define NSOFTCALLS 200
+/*
+ * Defined states for softcall processing.
+ */
+#define SOFT_IDLE 0x01 /* no processing is needed */
+#define SOFT_PEND 0x02 /* softcall list needs processing */
+#define SOFT_DRAIN 0x04 /* the list is being processed */
typedef struct softcall {
void (*sc_func)(void *); /* function to call */
@@ -48,8 +72,12 @@ typedef struct softcall {
} softcall_t;
static softcall_t softcalls[NSOFTCALLS], *softhead, *softtail, *softfree;
+static uint_t softcall_state;
-static kmutex_t softcall_lock; /* protects softcall lists */
+/*
+ * protects softcall lists and control variable softcall_state.
+ */
+static kmutex_t softcall_lock;
static void (*kdi_softcall_func)(void);
@@ -101,8 +129,20 @@ softcall(void (*func)(void *), void *arg)
mutex_exit(&softcall_lock);
} else {
softhead = softtail = sc;
- mutex_exit(&softcall_lock);
- siron();
+ if (softcall_state == SOFT_DRAIN)
+ /*
+ * softint is already running; no need to
+ * raise a siron. Due to lock protection of
+ * softhead / softcall state, we know
+ * that softint() will see the new addition to
+ * the softhead queue.
+ */
+ mutex_exit(&softcall_lock);
+ else {
+ softcall_state = SOFT_PEND;
+ mutex_exit(&softcall_lock);
+ siron();
+ }
}
}
@@ -116,10 +156,17 @@ kdi_softcall(void (*func)(void))
}
/*
- * Called to process software interrupts
- * take one off queue, call it, repeat
- * Note queue may change during call
+ * Called to process software interrupts take one off queue, call it,
+ * repeat.
+ *
+ * Note queue may change during call; softcall_lock and state variables
+ * softcall_state ensures that
+ * -we don't have multiple cpus pulling from the list (thus causing
+ * a violation of FIFO order).
+ * -we don't miss a new entry having been added to the head.
+ * -we don't miss a wakeup.
*/
+
void
softint(void)
{
@@ -127,8 +174,17 @@ softint(void)
void (*func)();
caddr_t arg;
+ /*
+ * Check if we are asked to process the softcall list.
+ */
+ mutex_enter(&softcall_lock);
+ if (softcall_state != SOFT_PEND) {
+ mutex_exit(&softcall_lock);
+ goto out;
+ }
+ softcall_state = SOFT_DRAIN;
+
for (;;) {
- mutex_enter(&softcall_lock);
if ((sc = softhead) != NULL) {
func = sc->sc_func;
arg = sc->sc_arg;
@@ -136,12 +192,16 @@ softint(void)
sc->sc_next = softfree;
softfree = sc;
}
- mutex_exit(&softcall_lock);
- if (sc == NULL)
+ if (sc == NULL) {
+ softcall_state = SOFT_IDLE;
+ mutex_exit(&softcall_lock);
break;
+ }
+ mutex_exit(&softcall_lock);
func(arg);
+ mutex_enter(&softcall_lock);
}
-
+out:
if ((func = kdi_softcall_func) != NULL) {
kdi_softcall_func = NULL;
func();
diff --git a/usr/src/uts/sun4/os/ddi_impl.c b/usr/src/uts/sun4/os/ddi_impl.c
index 54254e8aed..68780daa9b 100644
--- a/usr/src/uts/sun4/os/ddi_impl.c
+++ b/usr/src/uts/sun4/os/ddi_impl.c
@@ -1699,9 +1699,6 @@ i_ddi_get_nintrs(dev_info_t *dip)
uint_t
softlevel1(caddr_t arg)
{
- extern int siron_pending;
-
- siron_pending = 0;
softint();
return (1);
}
diff --git a/usr/src/uts/sun4/os/intr.c b/usr/src/uts/sun4/os/intr.c
index ac4bb6b888..6822380c39 100644
--- a/usr/src/uts/sun4/os/intr.c
+++ b/usr/src/uts/sun4/os/intr.c
@@ -60,6 +60,25 @@ uint_t swinum_base;
uint_t maxswinum;
uint_t siron_inum;
uint_t poke_cpu_inum;
+/*
+ * Note:-
+ * siron_pending was originally created to prevent a resource over consumption
+ * bug in setsoftint(exhaustion of interrupt pool free list).
+ * It's original intention is obsolete with the use of iv_pending in
+ * setsoftint. However, siron_pending stayed around, acting as a second
+ * gatekeeper preventing soft interrupts from being queued. In this capacity,
+ * it can lead to hangs on MP systems, where due to global visibility issues
+ * it can end up set while iv_pending is reset, preventing soft interrupts from
+ * ever being processed. In addition to its gatekeeper role, init_intr also
+ * uses it to flag the situation where siron() was called before siron_inum has
+ * been defined.
+ *
+ * siron() does not need an extra gatekeeper; any cpu that wishes should be
+ * allowed to queue a soft interrupt. It is softint()'s job to ensure
+ * correct handling of the queues. Therefore, siron_pending has been
+ * stripped of its gatekeeper task, retaining only its intr_init job, where
+ * it indicates that there is a pending need to call siron().
+ */
int siron_pending;
int intr_policy = INTR_WEIGHTED_DIST; /* interrupt distribution policy */
@@ -92,8 +111,10 @@ intr_init(cpu_t *cp)
* init_intr_pool, so we have to wait until now before we can dispatch
* the pending soft interrupt (if any).
*/
- if (siron_pending)
- setsoftint(siron_inum);
+ if (siron_pending) {
+ siron_pending = 0;
+ siron();
+ }
}
/*
@@ -233,11 +254,10 @@ init_intr_pool(cpu_t *cp)
void
siron(void)
{
- if (!siron_pending) {
+ if (siron_inum != 0)
+ setsoftint(siron_inum);
+ else
siron_pending = 1;
- if (siron_inum != 0)
- setsoftint(siron_inum);
- }
}
/*