changeset 2755:762b540b48d8 onnv_49

6469461 Fix issues with multiple MSI-X interrupts on sparc 6472171 remove unnecessary shifting from px driver
author egillett
date Mon, 18 Sep 2006 22:19:54 -0700
parents 17ea701f3e2b
children e560a040c473
files usr/src/uts/common/io/pci_intr_lib.c usr/src/uts/common/sys/pci_intr_lib.h usr/src/uts/sun4/io/px/px_intr.c usr/src/uts/sun4/io/px/px_msiq.c usr/src/uts/sun4u/io/px/px_lib4u.c usr/src/uts/sun4v/io/px/px_lib4v.c
diffstat 6 files changed, 50 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/pci_intr_lib.c	Mon Sep 18 17:21:08 2006 -0700
+++ b/usr/src/uts/common/io/pci_intr_lib.c	Mon Sep 18 22:19:54 2006 -0700
@@ -240,11 +240,11 @@
 	ushort_t		msi_ctrl, caps_ptr;
 	ddi_acc_handle_t	h;
 
-	DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: rdip = 0x%p\n",
-	    (void *)rdip));
+	DDI_INTR_NEXDBG((CE_CONT, "pci_msi_unconfigure: rdip = 0x%p type 0x%x "
+	    "inum 0x%x\n", (void *)rdip, type, inum));
 
 	if (pci_get_msi_ctrl(rdip, type, &msi_ctrl, &caps_ptr, &h) !=
-		DDI_SUCCESS)
+	    DDI_SUCCESS)
 		return (DDI_FAILURE);
 
 	if (type == DDI_INTR_TYPE_MSI) {
@@ -278,7 +278,8 @@
 		ddi_put32(msix_p->msix_tbl_hdl,
 		    (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), 0);
 
-		ddi_put64(msix_p->msix_tbl_hdl, (uint64_t *)off, 0);
+		ddi_put64(msix_p->msix_tbl_hdl,
+		    (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), 0);
 	}
 
 	pci_config_teardown(&h);
@@ -322,15 +323,19 @@
  *
  * This function sets the MSI_ENABLE bit in the capability structure
  * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure.
+ *
+ * NOTE: It is the nexus driver's responsibility to clear the MSI/X
+ * interrupt's mask bit in the MSI/X capability structure before the
+ * interrupt can be used.
  */
 int
-pci_msi_enable_mode(dev_info_t *rdip, int type, int inum)
+pci_msi_enable_mode(dev_info_t *rdip, int type)
 {
 	ushort_t		caps_ptr, msi_ctrl;
 	ddi_acc_handle_t	cfg_hdle;
 
-	DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: rdip = 0x%p, "
-	    "inum  = 0x%x\n", (void *)rdip, inum));
+	DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable_mode: rdip = 0x%p\n",
+	    (void *)rdip));
 
 	if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
 	    &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
@@ -344,28 +349,12 @@
 		PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
 
 	} else if (type == DDI_INTR_TYPE_MSIX) {
-		uintptr_t	off;
-		ddi_intr_msix_t	*msix_p;
-
 		if (msi_ctrl & PCI_MSIX_ENABLE_BIT)
 			goto finished;
 
 		msi_ctrl |= PCI_MSIX_ENABLE_BIT;
 		PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL,
-			msi_ctrl);
-
-		msix_p = i_ddi_get_msix(rdip);
-
-		/* Offset into the "inum"th entry in the MSI-X table */
-		off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
-		    PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
-
-		/* Clear the Mask bit */
-		ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x0);
-
-		DDI_INTR_NEXDBG((CE_CONT, "pci_msi_enable: "
-		    "msix_vector_mask 0x%x\n",
-		    ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off)));
+		    msi_ctrl);
 	}
 
 finished:
@@ -382,15 +371,27 @@
  *
  * This function resets the MSI_ENABLE bit in the capability structure
  * (for MSI) and MSIX_ENABLE bit in the MSI-X capability structure.
+ *
+ * NOTE: It is the nexus driver's responsibility to set the MSI/X
+ * interrupt's mask bit in the MSI/X capability structure before the
+ * interrupt can be disabled.
  */
 int
-pci_msi_disable_mode(dev_info_t *rdip, int type, int inum)
+pci_msi_disable_mode(dev_info_t *rdip, int type, uint_t flags)
 {
 	ushort_t		caps_ptr, msi_ctrl;
 	ddi_acc_handle_t	cfg_hdle;
 
 	DDI_INTR_NEXDBG((CE_CONT, "pci_msi_disable_mode: rdip = 0x%p "
-	    "inum = 0x%x\n", (void *)rdip, inum));
+	    "flags = 0x%x\n", (void *)rdip, flags));
+
+	/*
+	 * Do not turn off the master enable bit if other interrupts are
+	 * still active.
+	 */
+	if ((flags != DDI_INTR_FLAG_BLOCK) &&
+	    ((i_ddi_intr_get_current_nintrs(rdip) - 1) > 0))
+		return (DDI_SUCCESS);
 
 	if (pci_get_msi_ctrl(rdip, type, &msi_ctrl,
 	    &caps_ptr, &cfg_hdle) != DDI_SUCCESS)
@@ -403,20 +404,12 @@
 		msi_ctrl &= ~PCI_MSI_ENABLE_BIT;
 		PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSI_CTRL, msi_ctrl);
 	} else if (type == DDI_INTR_TYPE_MSIX) {
-		uintptr_t		off;
-		ddi_intr_msix_t		*msix_p;
-
 		if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT))
 			goto finished;
 
-		msix_p = i_ddi_get_msix(rdip);
-
-		/* Offset into the "inum"th entry in the MSI-X table */
-		off = (uintptr_t)msix_p->msix_tbl_addr + (inum *
-		    PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET;
-
-		/* Set the Mask bit */
-		ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, 0x1);
+		msi_ctrl &= ~PCI_MSIX_ENABLE_BIT;
+		PCI_CAP_PUT16(cfg_hdle, NULL, caps_ptr, PCI_MSIX_CTRL,
+		    msi_ctrl);
 	}
 
 finished:
@@ -1107,7 +1100,7 @@
 /*
  * pci_devclass_to_ipl:
  *	translate from device class to ipl
- *	NOTE: This function is  added here as pci_intx_get_ispec()
+ *	NOTE: This function is added here as pci_intx_get_ispec()
  *	calls this to figure out the priority.
  *	It is moved over from x86 pci.c
  */
--- a/usr/src/uts/common/sys/pci_intr_lib.h	Mon Sep 18 17:21:08 2006 -0700
+++ b/usr/src/uts/common/sys/pci_intr_lib.h	Mon Sep 18 22:19:54 2006 -0700
@@ -37,8 +37,8 @@
 		    int inum, uint64_t addr, uint64_t data);
 extern	int	pci_msi_unconfigure(dev_info_t *rdip, int type, int inum);
 extern	int	pci_is_msi_enabled(dev_info_t *rdip, int type);
-extern	int	pci_msi_enable_mode(dev_info_t *rdip, int type, int inum);
-extern	int	pci_msi_disable_mode(dev_info_t *rdip, int type, int inum);
+extern	int	pci_msi_enable_mode(dev_info_t *rdip, int type);
+extern	int	pci_msi_disable_mode(dev_info_t *rdip, int type, uint_t flags);
 extern	int	pci_msi_set_mask(dev_info_t *rdip, int type, int inum);
 extern	int	pci_msi_clr_mask(dev_info_t *rdip, int type, int inum);
 extern	int	pci_msi_get_pending(dev_info_t *rdip, int type, int inum,
--- a/usr/src/uts/sun4/io/px/px_intr.c	Mon Sep 18 17:21:08 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px_intr.c	Mon Sep 18 22:19:54 2006 -0700
@@ -677,7 +677,7 @@
 
 		break;
 	case DDI_INTROP_FREE:
-		(void) pci_msi_disable_mode(rdip, hdlp->ih_type, hdlp->ih_inum);
+		(void) pci_msi_disable_mode(rdip, hdlp->ih_type, NULL);
 		(void) pci_msi_unconfigure(rdip, hdlp->ih_type, hdlp->ih_inum);
 
 		if (hdlp->ih_type == DDI_INTR_TYPE_MSI)
@@ -761,16 +761,18 @@
 		    PCI_MSI_VALID)) != DDI_SUCCESS)
 			return (ret);
 
-		if (pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) {
+		if ((pci_is_msi_enabled(rdip, hdlp->ih_type) != DDI_SUCCESS) ||
+		    (hdlp->ih_type == DDI_INTR_TYPE_MSIX)) {
 			nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
 
 			if ((ret = pci_msi_configure(rdip, hdlp->ih_type,
 			    nintrs, hdlp->ih_inum, msi_addr,
-			    msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
+			    hdlp->ih_type == DDI_INTR_TYPE_MSIX ?
+			    msi_num : msi_num & ~(nintrs - 1))) != DDI_SUCCESS)
 				return (ret);
 
-			if ((ret = pci_msi_enable_mode(rdip, hdlp->ih_type,
-			    hdlp->ih_inum)) != DDI_SUCCESS)
+			if ((ret = pci_msi_enable_mode(rdip, hdlp->ih_type))
+			    != DDI_SUCCESS)
 				return (ret);
 		}
 
@@ -838,14 +840,14 @@
 				return (ret);
 		}
 
-		ret = pci_msi_enable_mode(rdip, hdlp->ih_type, hdlp->ih_inum);
+		ret = pci_msi_enable_mode(rdip, hdlp->ih_type);
 		break;
 	case DDI_INTROP_BLOCKDISABLE:
 		nintrs = i_ddi_intr_get_current_nintrs(hdlp->ih_dip);
 		msi_num = hdlp->ih_vector;
 
 		if ((ret = pci_msi_disable_mode(rdip, hdlp->ih_type,
-		    hdlp->ih_inum)) != DDI_SUCCESS)
+		    hdlp->ih_cap & DDI_INTR_FLAG_BLOCK)) != DDI_SUCCESS)
 			return (ret);
 
 		for (i = 0; i < nintrs; i++, msi_num++) {
--- a/usr/src/uts/sun4/io/px/px_msiq.c	Mon Sep 18 17:21:08 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px_msiq.c	Mon Sep 18 22:19:54 2006 -0700
@@ -49,7 +49,6 @@
 px_msiq_attach(px_t *px_p)
 {
 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
-	caddr_t		msiq_addr;
 	size_t		msiq_size;
 	int		i, ret = DDI_SUCCESS;
 
@@ -81,21 +80,17 @@
 	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);
-
 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
 	msiq_state_p->msiq_buf_p = kmem_zalloc(msiq_state_p->msiq_cnt *
 	    msiq_size, KM_SLEEP);
 
-	msiq_addr = (caddr_t)(((uint64_t)msiq_state_p->msiq_buf_p +
-	    (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT);
-
 	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;
 		msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
 
 		msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *)
-		    ((caddr_t)msiq_addr + (i * msiq_size));
+		    ((caddr_t)msiq_state_p->msiq_buf_p + (i * msiq_size));
 	}
 
 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
@@ -208,7 +203,6 @@
 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
 		if (msiq_state_p->msiq_p[i].msiq_id == msiq_id) {
 			msiq_state_p->msiq_p[i].msiq_state = MSIQ_STATE_FREE;
-			msiq_state_p->msiq_p[i].msiq_curr_head_idx = 0;
 			break;
 		}
 	}
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c	Mon Sep 18 17:21:08 2006 -0700
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c	Mon Sep 18 22:19:54 2006 -0700
@@ -664,7 +664,6 @@
 	px_t		*px_p = DIP_TO_STATE(dip);
 	pxu_t		*pxu_p = (pxu_t *)px_p->px_plat_p;
 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
-	caddr_t		msiq_addr;
 	px_dvma_addr_t	pg_index;
 	size_t		size;
 	int		ret;
@@ -680,9 +679,6 @@
 	 * entry.  Note: The size of the mapping is assumed to be a multiple
 	 * of the page size.
 	 */
-	msiq_addr = (caddr_t)(((uint64_t)msiq_state_p->msiq_buf_p +
-	    (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT);
-
 	size = msiq_state_p->msiq_cnt *
 	    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
 
@@ -696,8 +692,8 @@
 	    MMU_BTOP((ulong_t)pxu_p->msiq_mapped_p));
 
 	if ((ret = px_lib_iommu_map(px_p->px_dip, PCI_TSBID(0, pg_index),
-	    MMU_BTOP(size), PCI_MAP_ATTR_WRITE, (void *)msiq_addr, 0,
-	    MMU_MAP_BUF)) != DDI_SUCCESS) {
+	    MMU_BTOP(size), PCI_MAP_ATTR_WRITE, msiq_state_p->msiq_buf_p,
+	    0, MMU_MAP_BUF)) != DDI_SUCCESS) {
 		DBG(DBG_LIB_MSIQ, dip,
 		    "hvio_msiq_init failed, ret 0x%lx\n", ret);
 
@@ -749,16 +745,14 @@
 {
 	px_t		*px_p = DIP_TO_STATE(dip);
 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
-	uint64_t	*msiq_addr;
 	size_t		msiq_size;
 
 	DBG(DBG_LIB_MSIQ, dip, "px_msiq_info: dip 0x%p msiq_id 0x%x\n",
 	    dip, msiq_id);
 
-	msiq_addr = (uint64_t *)(((uint64_t)msiq_state_p->msiq_buf_p +
-	    (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT);
 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
-	ra_p = (r_addr_t *)((caddr_t)msiq_addr + (msiq_id * msiq_size));
+	ra_p = (r_addr_t *)((caddr_t)msiq_state_p->msiq_buf_p +
+	    (msiq_id * msiq_size));
 
 	*msiq_rec_cnt_p = msiq_state_p->msiq_rec_cnt;
 
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c	Mon Sep 18 17:21:08 2006 -0700
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c	Mon Sep 18 22:19:54 2006 -0700
@@ -547,7 +547,7 @@
 {
 	px_t		*px_p = DIP_TO_STATE(dip);
 	px_msiq_state_t	*msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
-	uint64_t	*msiq_addr, ra;
+	r_addr_t	ra;
 	size_t		msiq_size;
 	uint_t		rec_cnt;
 	int		i, err = DDI_SUCCESS;
@@ -555,13 +555,11 @@
 
 	DBG(DBG_LIB_MSIQ, dip, "px_lib_msiq_init: dip 0x%p\n", dip);
 
-	msiq_addr = (uint64_t *)(((uint64_t)msiq_state_p->msiq_buf_p +
-	    (MMU_PAGE_SIZE - 1)) >> MMU_PAGE_SHIFT << MMU_PAGE_SHIFT);
-
 	msiq_size = msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t);
 
 	for (i = 0; i < msiq_state_p->msiq_cnt; i++) {
-		ra = (r_addr_t)va_to_pa((caddr_t)msiq_addr + (i * msiq_size));
+		ra = (r_addr_t)va_to_pa((caddr_t)msiq_state_p->msiq_buf_p +
+		    (i * msiq_size));
 
 		if ((ret = hvio_msiq_conf(DIP_TO_HANDLE(dip),
 		    (i + msiq_state_p->msiq_1st_msiq_id),