diff options
| author | Scott Carter, SD IOSW <Scott.Carter@Sun.COM> | 2010-01-15 16:27:28 -0800 |
|---|---|---|
| committer | Scott Carter, SD IOSW <Scott.Carter@Sun.COM> | 2010-01-15 16:27:28 -0800 |
| commit | d17daf0b0e859a92357ab542e9070251d02dfa1f (patch) | |
| tree | 3ad195e5788637ca7272b4acbdd7f6beb835bae3 | |
| parent | bba9e99ca8b1c0ead08de153667f8e4f78da4b2c (diff) | |
| download | illumos-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.c | 48 | ||||
| -rw-r--r-- | usr/src/uts/sun4/io/px/px_ib.h | 9 | ||||
| -rw-r--r-- | usr/src/uts/sun4/io/px/px_intr.c | 34 | ||||
| -rw-r--r-- | usr/src/uts/sun4/io/px/px_msiq.c | 28 | ||||
| -rw-r--r-- | usr/src/uts/sun4/io/px/px_msiq.h | 3 |
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; /* |
