summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlq150181 <none@none>2005-11-27 18:29:20 -0800
committerlq150181 <none@none>2005-11-27 18:29:20 -0800
commite23a7e348c32cb3a1a7072dcac6905a150a028d7 (patch)
tree42f9a8a991cd2b8de00f045760de644937cef8eb
parent64dbca9e47a5b508a6b6994fd8c3b903027ef952 (diff)
downloadillumos-joyent-e23a7e348c32cb3a1a7072dcac6905a150a028d7.tar.gz
6348316 cyclic subsystem baffled by x86 softint behavior
-rw-r--r--usr/src/uts/common/io/avintr.c111
-rw-r--r--usr/src/uts/common/sys/avintr.h1
-rw-r--r--usr/src/uts/common/sys/ddi_intr_impl.h4
-rw-r--r--usr/src/uts/i86pc/io/cbe.c11
-rw-r--r--usr/src/uts/i86pc/os/ddi_impl.c30
-rw-r--r--usr/src/uts/i86pc/os/mp_machdep.c26
-rw-r--r--usr/src/uts/i86pc/sys/smp_impldefs.h7
7 files changed, 134 insertions, 56 deletions
diff --git a/usr/src/uts/common/io/avintr.c b/usr/src/uts/common/io/avintr.c
index e790c27e76..9236b3f4f2 100644
--- a/usr/src/uts/common/io/avintr.c
+++ b/usr/src/uts/common/io/avintr.c
@@ -48,7 +48,11 @@
#include <sys/stack.h>
#include <sys/ddi_impldefs.h>
-static int insert_av(void *intr_id, struct av_head *vectp, avfunc f,
+typedef struct av_softinfo {
+ cpuset_t av_pending; /* pending bitmasks */
+} av_softinfo_t;
+
+static void insert_av(void *intr_id, struct av_head *vectp, avfunc f,
caddr_t arg1, caddr_t arg2, uint64_t *ticksp, int pri_level,
dev_info_t *dip);
static void remove_av(void *intr_id, struct av_head *vectp, avfunc f,
@@ -78,11 +82,37 @@ struct av_head autovect[MAX_VECT];
struct av_head softvect[LOCK_LEVEL + 1];
kmutex_t av_lock;
ddi_softint_hdl_impl_t softlevel1_hdl =
- {0, NULL, NULL, 0, 0, NULL, NULL, NULL};
+ {0, NULL, NULL, NULL, 0, NULL, NULL, NULL};
+
+/*
+ * clear/check softint pending flag corresponding for
+ * the current CPU
+ */
+void
+av_clear_softint_pending(av_softinfo_t *infop)
+{
+ CPUSET_ATOMIC_DEL(infop->av_pending, CPU->cpu_seqid);
+}
+
+boolean_t
+av_check_softint_pending(av_softinfo_t *infop, boolean_t check_all)
+{
+ if (check_all)
+ return (!CPUSET_ISNULL(infop->av_pending));
+ else
+ return (CPU_IN_SET(infop->av_pending, CPU->cpu_seqid) != 0);
+}
+
+/*
+ * It first sets our av softint pending bit for the current CPU,
+ * then it sets the CPU softint pending bit for pri.
+ */
void
-set_pending(int pri)
+av_set_softint_pending(int pri, av_softinfo_t *infop)
{
+ CPUSET_ATOMIC_ADD(infop->av_pending, CPU->cpu_seqid);
+
atomic_or_32((uint32_t *)&CPU->cpu_softinfo.st_pending, 1 << pri);
}
@@ -191,8 +221,7 @@ add_avintr(void *intr_id, int lvl, avfunc xxintr, char *name, int vect,
cmn_err(CE_NOTE, multilevel, vect);
}
- if (!insert_av(intr_id, vecp, f, arg1, arg2, ticksp, lvl, dip))
- return (0);
+ insert_av(intr_id, vecp, f, arg1, arg2, ticksp, lvl, dip);
s = splhi();
/*
* do what ever machine specific things are necessary
@@ -233,6 +262,7 @@ add_avsoftintr(void *intr_id, int lvl, avfunc xxintr, char *name,
caddr_t arg1, caddr_t arg2)
{
int slvl;
+ ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)intr_id;
if ((slvl = slvltovect(lvl)) != -1)
return (add_avintr(intr_id, lvl, xxintr,
@@ -254,15 +284,19 @@ add_avsoftintr(void *intr_id, int lvl, avfunc xxintr, char *name,
printf(badsoft, lvl, name);
return (0);
}
- if (!insert_av(intr_id, &softvect[lvl], xxintr, arg1, arg2, NULL,
- lvl, NULL)) {
- return (0);
+
+ if (hdlp->ih_pending == NULL) {
+ hdlp->ih_pending =
+ kmem_zalloc(sizeof (av_softinfo_t), KM_SLEEP);
}
+
+ insert_av(intr_id, &softvect[lvl], xxintr, arg1, arg2, NULL, lvl, NULL);
+
return (1);
}
/* insert an interrupt vector into chain */
-static int
+static void
insert_av(void *intr_id, struct av_head *vectp, avfunc f, caddr_t arg1,
caddr_t arg2, uint64_t *ticksp, int pri_level, dev_info_t *dip)
{
@@ -288,7 +322,7 @@ insert_av(void *intr_id, struct av_head *vectp, avfunc f, caddr_t arg1,
vectp->avh_hi_pri = vectp->avh_lo_pri = (ushort_t)pri_level;
mutex_exit(&av_lock);
- return (1);
+ return;
}
/* find where it goes in list */
@@ -309,7 +343,7 @@ insert_av(void *intr_id, struct av_head *vectp, avfunc f, caddr_t arg1,
}
p->av_vector = f;
mutex_exit(&av_lock);
- return (1);
+ return;
}
}
/* insert new intpt at beginning of chain */
@@ -322,18 +356,15 @@ insert_av(void *intr_id, struct av_head *vectp, avfunc f, caddr_t arg1,
vectp->avh_lo_pri = (ushort_t)pri_level;
}
mutex_exit(&av_lock);
-
- return (1);
}
-/*
- * Remove a driver from the autovector list.
- */
-int
-rem_avsoftintr(void *intr_id, int lvl, avfunc xxintr)
+static int
+av_rem_softintr(void *intr_id, int lvl, avfunc xxintr, boolean_t rem_softinfo)
{
struct av_head *vecp = (struct av_head *)0;
int slvl;
+ ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)intr_id;
+ av_softinfo_t *infop = (av_softinfo_t *)hdlp->ih_pending;
if (xxintr == NULL)
return (0);
@@ -349,9 +380,40 @@ rem_avsoftintr(void *intr_id, int lvl, avfunc xxintr)
vecp = &softvect[lvl];
remove_av(intr_id, vecp, xxintr, lvl, 0);
+ if (rem_softinfo) {
+ kmem_free(infop, sizeof (av_softinfo_t));
+ hdlp->ih_pending = NULL;
+ }
+
return (1);
}
+int
+av_softint_movepri(void *intr_id, int old_lvl)
+{
+ int ret;
+ ddi_softint_hdl_impl_t *hdlp = (ddi_softint_hdl_impl_t *)intr_id;
+
+ ret = add_avsoftintr(intr_id, hdlp->ih_pri, hdlp->ih_cb_func,
+ DEVI(hdlp->ih_dip)->devi_name, hdlp->ih_cb_arg1, hdlp->ih_cb_arg2);
+
+ if (ret) {
+ (void) av_rem_softintr(intr_id, old_lvl, hdlp->ih_cb_func,
+ B_FALSE);
+ }
+
+ return (ret);
+}
+
+/*
+ * Remove a driver from the autovector list.
+ */
+int
+rem_avsoftintr(void *intr_id, int lvl, avfunc xxintr)
+{
+ return (av_rem_softintr(intr_id, lvl, xxintr, B_TRUE));
+}
+
void
rem_avintr(void *intr_id, int lvl, avfunc xxintr, int vect)
{
@@ -480,8 +542,7 @@ remove_av(void *intr_id, struct av_head *vectp, avfunc f, int pri_level,
void
siron(void)
{
- softlevel1_hdl.ih_pending = 1;
- (*setsoftint)(1);
+ (*setsoftint)(1, softlevel1_hdl.ih_pending);
}
/*
@@ -556,8 +617,14 @@ av_dispatch_softvect(uint_t pil)
hdlp = (ddi_softint_hdl_impl_t *)av->av_intr_id;
ASSERT(hdlp);
- if (hdlp->ih_pending) {
- hdlp->ih_pending = 0;
+ /*
+ * Each cpu has its own pending bit in hdlp->ih_pending,
+ * here av_check/clear_softint_pending is just checking
+ * and clearing the pending bit for the current cpu, who
+ * has just triggered a softint.
+ */
+ if (av_check_softint_pending(hdlp->ih_pending, B_FALSE)) {
+ av_clear_softint_pending(hdlp->ih_pending);
(void) (*intr)(arg1, arg2);
}
}
diff --git a/usr/src/uts/common/sys/avintr.h b/usr/src/uts/common/sys/avintr.h
index 77ce12eee3..9f907d58b1 100644
--- a/usr/src/uts/common/sys/avintr.h
+++ b/usr/src/uts/common/sys/avintr.h
@@ -94,6 +94,7 @@ extern int add_nmintr(int lvl, avfunc nmintr, char *name, caddr_t arg);
extern int add_avsoftintr(void *intr_id, int lvl, avfunc xxintr,
char *name, caddr_t arg1, caddr_t arg2);
extern int rem_avsoftintr(void *intr_id, int lvl, avfunc xxintr);
+extern int av_softint_movepri(void *intr_id, int old_lvl);
extern void update_avsoftintr_args(void *intr_id, int lvl, caddr_t arg2);
extern void rem_avintr(void *intr_id, int lvl, avfunc xxintr, int vect);
extern void wait_till_seen(int ipl);
diff --git a/usr/src/uts/common/sys/ddi_intr_impl.h b/usr/src/uts/common/sys/ddi_intr_impl.h
index 1afcca6faa..692e5d353b 100644
--- a/usr/src/uts/common/sys/ddi_intr_impl.h
+++ b/usr/src/uts/common/sys/ddi_intr_impl.h
@@ -116,6 +116,8 @@ typedef struct ddi_intr_handle_impl {
#define DDI_INTR_SUP_TYPES DDI_INTR_TYPE_FIXED|DDI_INTR_TYPE_MSI|\
DDI_INTR_TYPE_MSIX
+struct av_softinfo;
+
/*
* One such data structure is allocated per ddi_soft_intr_handle
* This is the incore copy of the softint info.
@@ -124,7 +126,7 @@ typedef struct ddi_softint_hdl_impl {
dev_info_t *ih_dip; /* dip associated with handle */
uint_t ih_pri; /* priority - bus dependent */
krwlock_t ih_rwlock; /* read/write lock per handle */
- uint_t ih_pending; /* whether softint is pending */
+ struct av_softinfo *ih_pending; /* whether softint is pending */
uint_t (*ih_cb_func)(caddr_t, caddr_t);
/* cb function for soft ints */
diff --git a/usr/src/uts/i86pc/io/cbe.c b/usr/src/uts/i86pc/io/cbe.c
index 83c6b4f276..5f1c2577bb 100644
--- a/usr/src/uts/i86pc/io/cbe.c
+++ b/usr/src/uts/i86pc/io/cbe.c
@@ -38,6 +38,7 @@
#include <sys/clock.h>
#include <sys/ddi_impldefs.h>
#include <sys/ddi_intr.h>
+#include <sys/avintr.h>
static int cbe_vector;
static int cbe_ticks = 0;
@@ -48,9 +49,9 @@ static void *cbe_xcall_farg;
static cpuset_t cbe_enabled;
static ddi_softint_hdl_impl_t cbe_low_hdl =
- {0, NULL, NULL, 0, 0, NULL, NULL, NULL};
+ {0, NULL, NULL, NULL, 0, NULL, NULL, NULL};
static ddi_softint_hdl_impl_t cbe_clock_hdl =
- {0, NULL, NULL, 0, 0, NULL, NULL, NULL};
+ {0, NULL, NULL, NULL, 0, NULL, NULL, NULL};
cyclic_id_t cbe_hres_cyclic;
int cbe_psm_timer_mode = TIMER_ONESHOT;
@@ -112,12 +113,10 @@ cbe_softint(void *arg, cyc_level_t level)
{
switch (level) {
case CY_LOW_LEVEL:
- cbe_low_hdl.ih_pending = 1;
- (*setsoftint)(CBE_LOW_PIL);
+ (*setsoftint)(CBE_LOW_PIL, cbe_low_hdl.ih_pending);
break;
case CY_LOCK_LEVEL:
- cbe_clock_hdl.ih_pending = 1;
- (*setsoftint)(CBE_LOCK_PIL);
+ (*setsoftint)(CBE_LOCK_PIL, cbe_clock_hdl.ih_pending);
break;
default:
panic("cbe_softint: unexpected soft level %d", level);
diff --git a/usr/src/uts/i86pc/os/ddi_impl.c b/usr/src/uts/i86pc/os/ddi_impl.c
index 085a9351b3..c60ae037e8 100644
--- a/usr/src/uts/i86pc/os/ddi_impl.c
+++ b/usr/src/uts/i86pc/os/ddi_impl.c
@@ -850,23 +850,19 @@ i_ddi_remove_softint(ddi_softint_hdl_impl_t *hdlp)
}
-extern void (*setsoftint)(int);
+extern void (*setsoftint)(int, struct av_softinfo *);
+extern boolean_t av_check_softint_pending(struct av_softinfo *, boolean_t);
int
i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2)
{
- int ret = DDI_SUCCESS;
+ if (av_check_softint_pending(hdlp->ih_pending, B_FALSE))
+ return (DDI_EPENDING);
- if (hdlp->ih_pending) {
- ret = DDI_EPENDING;
- } else {
- update_avsoftintr_args((void *)hdlp,
- hdlp->ih_pri, arg2);
- hdlp->ih_pending = 1;
- }
+ update_avsoftintr_args((void *)hdlp, hdlp->ih_pri, arg2);
- (*setsoftint)(hdlp->ih_pri);
- return (ret);
+ (*setsoftint)(hdlp->ih_pri, hdlp->ih_pending);
+ return (DDI_SUCCESS);
}
/*
@@ -879,18 +875,16 @@ i_ddi_trigger_softint(ddi_softint_hdl_impl_t *hdlp, void *arg2)
int
i_ddi_set_softint_pri(ddi_softint_hdl_impl_t *hdlp, uint_t old_pri)
{
+ int ret;
+
/*
* If a softint is pending at the old priority then fail the request.
- * OR
- * If we failed to add a softint vector with the new priority; then
- * fail the request with a DDI_FAILURE
*/
- if (hdlp->ih_pending || i_ddi_add_softint(hdlp) != DDI_SUCCESS)
+ if (av_check_softint_pending(hdlp->ih_pending, B_TRUE))
return (DDI_FAILURE);
- /* Now, remove the softint at the old priority */
- (void) rem_avsoftintr((void *)hdlp, old_pri, hdlp->ih_cb_func);
- return (DDI_SUCCESS);
+ ret = av_softint_movepri((void *)hdlp, old_pri);
+ return (ret ? DDI_SUCCESS : DDI_FAILURE);
}
void
diff --git a/usr/src/uts/i86pc/os/mp_machdep.c b/usr/src/uts/i86pc/os/mp_machdep.c
index e6dc73b7f0..2a95e4083d 100644
--- a/usr/src/uts/i86pc/os/mp_machdep.c
+++ b/usr/src/uts/i86pc/os/mp_machdep.c
@@ -60,7 +60,7 @@ static uint64_t mach_getcpufreq(void);
static void mach_fixcpufreq(void);
static int mach_clkinit(int, int *);
static void mach_smpinit(void);
-static void mach_set_softintr(int ipl);
+static void mach_set_softintr(int ipl, struct av_softinfo *);
static void mach_cpu_start(int cpun);
static int mach_softlvl_to_vect(int ipl);
static void mach_get_platform(int owner);
@@ -105,7 +105,8 @@ void (*send_dirintf)() = return_instr;
void (*setspl)(int) = return_instr;
int (*addspl)(int, int, int, int) = (int (*)(int, int, int, int))return_instr;
int (*delspl)(int, int, int, int) = (int (*)(int, int, int, int))return_instr;
-void (*setsoftint)(int) = (void (*)(int))return_instr;
+void (*setsoftint)(int, struct av_softinfo *)=
+ (void (*)(int, struct av_softinfo *))return_instr;
int (*slvltovect)(int) = (int (*)(int))return_instr;
int (*setlvl)(int, int *) = (int (*)(int, int *))return_instr;
void (*setlvlx)(int, int) = (void (*)(int, int))return_instr;
@@ -932,6 +933,17 @@ mach_clkinit(int preferred_mode, int *set_mode)
}
}
+/*ARGSUSED*/
+static void
+mach_psm_set_softintr(int ipl, struct av_softinfo *pending)
+{
+ register struct psm_ops *pops;
+
+ /* invoke hardware interrupt */
+ pops = mach_set[0];
+ (*pops->psm_set_softintr)(ipl);
+}
+
static int
mach_softlvl_to_vect(register int ipl)
{
@@ -942,19 +954,19 @@ mach_softlvl_to_vect(register int ipl)
/* check for null handler for set soft interrupt call */
if (pops->psm_set_softintr == NULL) {
- setsoftint = set_pending;
+ setsoftint = av_set_softint_pending;
return (PSM_SV_SOFTWARE);
}
softvect = (*pops->psm_softlvl_to_irq)(ipl);
/* check for hardware scheme */
if (softvect > PSM_SV_SOFTWARE) {
- setsoftint = pops->psm_set_softintr;
+ setsoftint = mach_psm_set_softintr;
return (softvect);
}
if (softvect == PSM_SV_SOFTWARE)
- setsoftint = set_pending;
+ setsoftint = av_set_softint_pending;
else /* hardware and software mixed scheme */
setsoftint = mach_set_softintr;
@@ -962,12 +974,12 @@ mach_softlvl_to_vect(register int ipl)
}
static void
-mach_set_softintr(register int ipl)
+mach_set_softintr(register int ipl, struct av_softinfo *pending)
{
register struct psm_ops *pops;
/* set software pending bits */
- set_pending(ipl);
+ av_set_softint_pending(ipl, pending);
/* check if dosoftint will be called at the end of intr */
if (CPU_ON_INTR(CPU) || (curthread->t_intr))
diff --git a/usr/src/uts/i86pc/sys/smp_impldefs.h b/usr/src/uts/i86pc/sys/smp_impldefs.h
index 31300aed76..79e41e6852 100644
--- a/usr/src/uts/i86pc/sys/smp_impldefs.h
+++ b/usr/src/uts/i86pc/sys/smp_impldefs.h
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/sunddi.h>
#include <sys/cpuvar.h>
+#include <sys/avintr.h>
#include <sys/pic.h>
#include <sys/xc_levels.h>
@@ -77,10 +78,12 @@ extern void (*setlvlx)(int, int); /* set intr pri to specified level */
extern void (*setspl)(int); /* mask intr below or equal given ipl */
extern int (*addspl)(int, int, int, int); /* add intr mask of vector */
extern int (*delspl)(int, int, int, int); /* delete intr mask of vector */
-extern void (*setsoftint)(int); /* trigger a software intr */
+
+/* trigger a software intr */
+extern void (*setsoftint)(int, struct av_softinfo *);
extern uint_t xc_serv(caddr_t, caddr_t); /* cross call service routine */
-extern void set_pending(); /* set software interrupt pending */
+extern void av_set_softint_pending(); /* set software interrupt pending */
extern void microfind(void); /* initialize tenmicrosec */
/* map physical address */