summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Carter, SD IOSW <Scott.Carter@Sun.COM>2010-01-15 16:27:28 -0800
committerScott Carter, SD IOSW <Scott.Carter@Sun.COM>2010-01-15 16:27:28 -0800
commitd17daf0b0e859a92357ab542e9070251d02dfa1f (patch)
tree3ad195e5788637ca7272b4acbdd7f6beb835bae3
parentbba9e99ca8b1c0ead08de153667f8e4f78da4b2c (diff)
downloadillumos-joyent-d17daf0b0e859a92357ab542e9070251d02dfa1f.tar.gz
6887999 T5140 Panic in px_ib_intr_redist during reboot test.
6896543 ddi_intr_set_affinity could cause mem corruption
-rw-r--r--usr/src/uts/sun4/io/px/px_ib.c48
-rw-r--r--usr/src/uts/sun4/io/px/px_ib.h9
-rw-r--r--usr/src/uts/sun4/io/px/px_intr.c34
-rw-r--r--usr/src/uts/sun4/io/px/px_msiq.c28
-rw-r--r--usr/src/uts/sun4/io/px/px_msiq.h3
5 files changed, 66 insertions, 56 deletions
diff --git a/usr/src/uts/sun4/io/px/px_ib.c b/usr/src/uts/sun4/io/px/px_ib.c
index 9f5a3f53f8..9355a15741 100644
--- a/usr/src/uts/sun4/io/px/px_ib.c
+++ b/usr/src/uts/sun4/io/px/px_ib.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -808,6 +808,7 @@ px_ib_alloc_ih(dev_info_t *rdip, uint32_t inum,
ih_p->ih_dip = rdip;
ih_p->ih_inum = inum;
ih_p->ih_intr_state = PX_INTR_STATE_DISABLE;
+ ih_p->ih_intr_flags = PX_INTR_IDLE;
ih_p->ih_handler = int_handler;
ih_p->ih_handler_arg1 = int_handler_arg1;
ih_p->ih_handler_arg2 = int_handler_arg2;
@@ -1022,35 +1023,47 @@ px_ib_set_msix_target(px_t *px_p, ddi_intr_handle_impl_t *hdlp,
if ((ret = px_lib_msi_setmsiq(dip, msi_num,
msiq_id, msi_type)) != DDI_SUCCESS) {
+ mutex_exit(&cpu_lock);
+
(void) px_rem_msiq_intr(dip, rdip,
hdlp, msiq_rec_type, msi_num, msiq_id);
- mutex_exit(&cpu_lock);
return (ret);
}
if ((ret = px_ib_update_intr_state(px_p, rdip, hdlp->ih_inum,
px_msiqid_to_devino(px_p, msiq_id), hdlp->ih_pri,
PX_INTR_STATE_ENABLE, msiq_rec_type, msi_num)) != DDI_SUCCESS) {
+ mutex_exit(&cpu_lock);
+
(void) px_rem_msiq_intr(dip, rdip,
hdlp, msiq_rec_type, msi_num, msiq_id);
- mutex_exit(&cpu_lock);
return (ret);
}
mutex_exit(&cpu_lock);
+
+ /*
+ * Remove the old handler, but first ensure it is finished.
+ *
+ * Each handler sets its PENDING flag before it clears the MSI state.
+ * Then it clears that flag when finished. If a re-target occurs while
+ * the MSI state is DELIVERED, then it is not yet known which of the
+ * two handlers will take the interrupt. So the re-target operation
+ * sets a RETARGET flag on both handlers in that case. Monitoring both
+ * flags on both handlers then determines when the old handler can be
+ * be safely removed.
+ */
mutex_enter(&ib_p->ib_ino_lst_mutex);
ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, old_msiq_id));
old_ih_p = px_ib_intr_locate_ih(px_ib_ino_locate_ipil(ino_p,
hdlp->ih_pri), rdip, hdlp->ih_inum, msiq_rec_type, msi_num);
- old_ih_p->ih_retarget_flag = B_TRUE;
ino_p = px_ib_locate_ino(ib_p, px_msiqid_to_devino(px_p, msiq_id));
ih_p = px_ib_intr_locate_ih(px_ib_ino_locate_ipil(ino_p, hdlp->ih_pri),
rdip, hdlp->ih_inum, msiq_rec_type, msi_num);
- ih_p->ih_retarget_flag = B_TRUE;
if ((ret = px_lib_msi_getstate(dip, msi_num,
&msi_state)) != DDI_SUCCESS) {
@@ -1061,25 +1074,30 @@ px_ib_set_msix_target(px_t *px_p, ddi_intr_handle_impl_t *hdlp,
return (ret);
}
- if (msi_state == PCI_MSI_STATE_IDLE)
- ih_p->ih_retarget_flag = B_FALSE;
+ if (msi_state == PCI_MSI_STATE_DELIVERED) {
+ ih_p->ih_intr_flags |= PX_INTR_RETARGET;
+ old_ih_p->ih_intr_flags |= PX_INTR_RETARGET;
+ }
start_time = gethrtime();
- while ((ih_p->ih_retarget_flag == B_TRUE) &&
- (old_ih_p->ih_retarget_flag == B_TRUE)) {
- if ((end_time = (gethrtime() - start_time)) >
- px_ib_msix_retarget_timeout) {
+ while (((ih_p->ih_intr_flags & PX_INTR_RETARGET) &&
+ (old_ih_p->ih_intr_flags & PX_INTR_RETARGET)) ||
+ (old_ih_p->ih_intr_flags & PX_INTR_PENDING)) {
+
+ /* Wait for one second */
+ delay(drv_usectohz(1000000));
+
+ end_time = gethrtime() - start_time;
+ if (end_time > px_ib_msix_retarget_timeout) {
cmn_err(CE_WARN, "MSIX retarget %x is not completed, "
"even after waiting %llx ticks\n",
msi_num, end_time);
-
break;
}
-
- /* Wait for one second */
- delay(drv_usectohz(1000000));
}
+ ih_p->ih_intr_flags &= ~(PX_INTR_RETARGET);
+
mutex_exit(&ib_p->ib_ino_lst_mutex);
ret = px_rem_msiq_intr(dip, rdip,
diff --git a/usr/src/uts/sun4/io/px/px_ib.h b/usr/src/uts/sun4/io/px/px_ib.h
index 0c39a6395d..f597fcde76 100644
--- a/usr/src/uts/sun4/io/px/px_ib.h
+++ b/usr/src/uts/sun4/io/px/px_ib.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -68,7 +68,7 @@ struct px_ih {
uint_t ih_intr_state; /* only used for fixed interrupts */
msiq_rec_type_t ih_rec_type; /* MSI or PCIe record type */
msgcode_t ih_msg_code; /* MSI number or PCIe message code */
- boolean_t ih_retarget_flag; /* MSI/X retarget flag */
+ uint8_t ih_intr_flags; /* interrupt handler status flags */
px_ih_t *ih_next; /* Next entry in list */
uint64_t ih_ticks; /* ticks spent in this handler */
uint64_t ih_nsec; /* nsec spent in this handler */
@@ -80,6 +80,11 @@ struct px_ih {
#define PX_INTR_STATE_DISABLE 0 /* disabled */
#define PX_INTR_STATE_ENABLE 1 /* enabled */
+/* Only used for MSI/X to track interrupt handler status */
+#define PX_INTR_IDLE 0x0 /* handler is idle */
+#define PX_INTR_RETARGET 0x1 /* retarget in progress */
+#define PX_INTR_PENDING 0x2 /* handler is pending */
+
/*
* ino_pil structure: one per each ino and pil pair with interrupt registered
*/
diff --git a/usr/src/uts/sun4/io/px/px_intr.c b/usr/src/uts/sun4/io/px/px_intr.c
index 2f61459447..4248faf4e4 100644
--- a/usr/src/uts/sun4/io/px/px_intr.c
+++ b/usr/src/uts/sun4/io/px/px_intr.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -332,10 +332,6 @@ px_msiq_intr(caddr_t arg)
msg_code = msiq_rec_p->msiq_rec_data.msi.msi_data;
DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSI record, "
"msi 0x%x\n", msg_code);
-
- /* Clear MSI state */
- px_lib_msi_setstate(dip, (msinum_t)msg_code,
- PCI_MSI_STATE_IDLE);
break;
default:
msg_code = 0;
@@ -360,19 +356,19 @@ px_msiq_intr(caddr_t arg)
if ((ih_p->ih_msg_code == msg_code) &&
(ih_p->ih_rec_type == rec_type)) {
- dev_info_t *dip = ih_p->ih_dip;
+ dev_info_t *ih_dip = ih_p->ih_dip;
uint_t (*handler)() = ih_p->ih_handler;
caddr_t arg1 = ih_p->ih_handler_arg1;
caddr_t arg2 = ih_p->ih_handler_arg2;
- DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: ino=%x data=%x "
- "handler=%p arg1 =%p arg2=%p\n", ino_p->ino_ino,
- msg_code, handler, arg1, arg2);
+ DBG(DBG_MSIQ_INTR, ih_dip, "px_msiq_intr: ino=%x "
+ "data=%x handler=%p arg1 =%p arg2=%p\n",
+ ino_p->ino_ino, msg_code, handler, arg1, arg2);
- DTRACE_PROBE4(interrupt__start, dev_info_t, dip,
+ DTRACE_PROBE4(interrupt__start, dev_info_t, ih_dip,
void *, handler, caddr_t, arg1, caddr_t, arg2);
- ih_p->ih_retarget_flag = B_FALSE;
+ ih_p->ih_intr_flags = PX_INTR_PENDING;
/*
* Special case for PCIE Error Messages.
@@ -386,8 +382,13 @@ px_msiq_intr(caddr_t arg)
(msg_code == PCIE_MSG_CODE_ERR_FATAL))) {
ret = px_err_fabric_intr(px_p, msg_code,
msiq_rec_p->msiq_rec_rid);
- } else
+ } else {
+ /* Clear MSI state */
+ px_lib_msi_setstate(dip, (msinum_t)msg_code,
+ PCI_MSI_STATE_IDLE);
+
ret = (*handler)(arg1, arg2);
+ }
/*
* Account for time used by this interrupt. Protect
@@ -398,13 +399,16 @@ px_msiq_intr(caddr_t arg)
if (pil <= LOCK_LEVEL)
atomic_add_64(&ih_p->ih_ticks, intr_get_time());
- DTRACE_PROBE4(interrupt__complete, dev_info_t, dip,
+ DTRACE_PROBE4(interrupt__complete, dev_info_t, ih_dip,
void *, handler, caddr_t, arg1, int, ret);
+ /* clear handler status flags */
+ ih_p->ih_intr_flags = PX_INTR_IDLE;
+
msiq_p->msiq_new_head_index++;
- px_lib_clr_msiq_rec(dip, curr_head_p);
+ px_lib_clr_msiq_rec(ih_dip, curr_head_p);
} else {
- DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr:"
+ DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: "
"No matching MSIQ record found\n");
}
next_rec:
diff --git a/usr/src/uts/sun4/io/px/px_msiq.c b/usr/src/uts/sun4/io/px/px_msiq.c
index c8b38803c5..c647cc706a 100644
--- a/usr/src/uts/sun4/io/px/px_msiq.c
+++ b/usr/src/uts/sun4/io/px/px_msiq.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -77,10 +77,10 @@ px_msiq_attach(px_t *px_p)
msiq_state_p->msiq_1st_msg_qid = msiq_state_p->msiq_1st_msiq_id +
msiq_state_p->msiq_msi_qcnt;
- mutex_init(&msiq_state_p->msiq_mutex, NULL, MUTEX_DRIVER, NULL);
msiq_state_p->msiq_p = kmem_zalloc(msiq_state_p->msiq_cnt *
sizeof (px_msiq_t), KM_SLEEP);
+ mutex_enter(&ib_p->ib_ino_lst_mutex);
for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
msiq_state_p->msiq_p[i].msiq_id =
msiq_state_p->msiq_1st_msiq_id + i;
@@ -90,10 +90,12 @@ px_msiq_attach(px_t *px_p)
msiq_state_p->msiq_p[i].msiq_id));
}
+ msiq_state_p->msiq_redist_flag = B_TRUE;
+ mutex_exit(&ib_p->ib_ino_lst_mutex);
+
if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
px_msiq_detach(px_p);
- msiq_state_p->msiq_redist_flag = B_TRUE;
return (ret);
}
@@ -112,7 +114,6 @@ px_msiq_detach(px_t *px_p)
"px_lib_msiq_fini: failed\n");
}
- mutex_destroy(&msiq_state_p->msiq_mutex);
kmem_free(msiq_state_p->msiq_p,
msiq_state_p->msiq_cnt * sizeof (px_msiq_t));
@@ -154,7 +155,6 @@ px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msgcode_t msg_code,
DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_alloc\n");
ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
- mutex_enter(&msiq_state_p->msiq_mutex);
if (rec_type == MSG_REC) {
/*
@@ -180,7 +180,6 @@ px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msgcode_t msg_code,
DBG(DBG_MSIQ, px_p->px_dip,
"px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
- mutex_exit(&msiq_state_p->msiq_mutex);
return (DDI_SUCCESS);
}
@@ -216,7 +215,6 @@ px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type, msgcode_t msg_code,
DBG(DBG_MSIQ, px_p->px_dip,
"px_msiq_alloc: msiq_id 0x%x\n", *msiq_id_p);
- mutex_exit(&msiq_state_p->msiq_mutex);
return (DDI_SUCCESS);
}
@@ -240,8 +238,6 @@ px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type,
ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
- mutex_enter(&msiq_state_p->msiq_mutex);
-
if (rec_type == MSG_REC) {
msiq_cnt = msiq_state_p->msiq_msg_qcnt;
first_msiq_id = msiq_state_p->msiq_1st_msg_qid;
@@ -273,8 +269,6 @@ px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type,
DBG(DBG_MSIQ, px_p->px_dip,
"px_msiq_alloc_based_on_cpuid: No EQ is available "
"for CPU 0x%x\n", cpuid);
-
- mutex_exit(&msiq_state_p->msiq_mutex);
return (DDI_EINVAL);
}
@@ -295,7 +289,6 @@ px_msiq_alloc_based_on_cpuid(px_t *px_p, msiq_rec_type_t rec_type,
DBG(DBG_MSIQ, px_p->px_dip,
"px_msiq_alloc_based_on_cpuid: msiq_id 0x%x\n", *msiq_id_p);
- mutex_exit(&msiq_state_p->msiq_mutex);
return (DDI_SUCCESS);
}
@@ -311,21 +304,17 @@ px_msiq_free(px_t *px_p, msiqid_t msiq_id)
DBG(DBG_MSIQ, px_p->px_dip, "px_msiq_free: msiq_id 0x%x", msiq_id);
ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
- mutex_enter(&msiq_state_p->msiq_mutex);
if ((msiq_id < msiq_state_p->msiq_1st_msiq_id) || (msiq_id >=
(msiq_state_p->msiq_1st_msiq_id + msiq_state_p->msiq_cnt))) {
DBG(DBG_MSIQ, px_p->px_dip,
"px_msiq_free: Invalid msiq_id 0x%x", msiq_id);
-
- mutex_exit(&msiq_state_p->msiq_mutex);
return (DDI_FAILURE);
}
if (--msiq_state_p->msiq_p[msiq_id].msiq_refcnt == 0)
msiq_state_p->msiq_p[msiq_id].msiq_state = MSIQ_STATE_FREE;
- mutex_exit(&msiq_state_p->msiq_mutex);
return (DDI_SUCCESS);
}
@@ -342,12 +331,8 @@ px_msiq_redist(px_t *px_p)
ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex));
- mutex_enter(&msiq_state_p->msiq_mutex);
-
- if (msiq_state_p->msiq_redist_flag == B_FALSE) {
- mutex_exit(&msiq_state_p->msiq_mutex);
+ if (msiq_state_p->msiq_redist_flag == B_FALSE)
return;
- }
for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
ino_p = px_ib_locate_ino(ib_p,
@@ -365,7 +350,6 @@ px_msiq_redist(px_t *px_p)
}
msiq_state_p->msiq_redist_flag = B_FALSE;
- mutex_exit(&msiq_state_p->msiq_mutex);
}
/*
diff --git a/usr/src/uts/sun4/io/px/px_msiq.h b/usr/src/uts/sun4/io/px/px_msiq.h
index 2a44a86efe..f69ab57f9d 100644
--- a/usr/src/uts/sun4/io/px/px_msiq.h
+++ b/usr/src/uts/sun4/io/px/px_msiq.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -69,7 +69,6 @@ typedef struct px_msiq_state {
px_msiq_t *msiq_p; /* Pointer to MSIQs array */
void *msiq_buf_p; /* Pointer to MSIQs array */
- kmutex_t msiq_mutex; /* Mutex for MSIQ alloc/free */
} px_msiq_state_t;
/*