changeset 2588:6ca5ef0f409c onnv_47

6453554 px driver MSI handler can cause eq_over 6454481 Freeing MSI/MSI-X interrupts is not ok 6459301 i_ddi_intr_devi_fini should check for interrupts in use
author egillett
date Mon, 21 Aug 2006 21:16:28 -0700
parents 93d8b810a71d
children bab6bd68d0e5
files usr/src/uts/common/os/ddi_intr.c usr/src/uts/common/os/ddi_intr_impl.c usr/src/uts/sun4/io/px/px.c usr/src/uts/sun4/io/px/px_intr.c usr/src/uts/sun4/io/px/px_lib.h usr/src/uts/sun4/io/px/px_msiq.c usr/src/uts/sun4/io/px/px_msiq.h usr/src/uts/sun4u/io/px/px_lib4u.c usr/src/uts/sun4v/io/px/px_lib4v.c
diffstat 9 files changed, 92 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/os/ddi_intr.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/common/os/ddi_intr.c	Mon Aug 21 21:16:28 2006 -0700
@@ -375,6 +375,9 @@
 		return (DDI_EINVAL);
 	}
 
+	/* Set the number of interrupts to free */
+	hdlp->ih_scratch1 = 1;
+
 	ret = i_ddi_intr_ops(hdlp->ih_dip, hdlp->ih_dip,
 	    DDI_INTROP_FREE, hdlp, NULL);
 
@@ -387,14 +390,11 @@
 			i_ddi_intr_set_current_nintrs(hdlp->ih_dip,
 			    i_ddi_intr_get_current_nintrs(hdlp->ih_dip) - 1);
 
-			if (i_ddi_intr_get_current_nintrs(hdlp->ih_dip) == 0) {
-				i_ddi_intr_devi_fini(hdlp->ih_dip);
-			} else {
-				if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
-					i_ddi_set_intr_handle(hdlp->ih_dip,
-					    hdlp->ih_inum, NULL);
-			}
+			if (hdlp->ih_type & DDI_INTR_TYPE_FIXED)
+				i_ddi_set_intr_handle(hdlp->ih_dip,
+				    hdlp->ih_inum, NULL);
 
+			i_ddi_intr_devi_fini(hdlp->ih_dip);
 			i_ddi_free_intr_phdl(hdlp);
 		}
 		rw_destroy(&hdlp->ih_rwlock);
--- a/usr/src/uts/common/os/ddi_intr_impl.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/common/os/ddi_intr_impl.c	Mon Aug 21 21:16:28 2006 -0700
@@ -69,7 +69,8 @@
 	DDI_INTR_APIDBG((CE_CONT, "i_ddi_intr_devi_fini: dip %p\n",
 	    (void *)dip));
 
-	if (DEVI(dip)->devi_intr_p == NULL)
+	if ((DEVI(dip)->devi_intr_p == NULL) ||
+	    i_ddi_intr_get_current_nintrs(dip))
 		return;
 
 	/*
--- a/usr/src/uts/sun4/io/px/px.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px.c	Mon Aug 21 21:16:28 2006 -0700
@@ -394,6 +394,7 @@
 			break;
 		}
 
+		px_msiq_resume(px_p);
 		px_lib_resume(dip);
 		(void) pcie_pwr_resume(dip);
 		px_p->px_state = PX_ATTACHED;
--- a/usr/src/uts/sun4/io/px/px_intr.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px_intr.c	Mon Aug 21 21:16:28 2006 -0700
@@ -232,41 +232,48 @@
 	px_msiq_t	*msiq_p = ino_p->ino_msiq_p;
 	dev_info_t	*dip = px_p->px_dip;
 	msiq_rec_t	msiq_rec, *msiq_rec_p = &msiq_rec;
-	msiqhead_t	curr_msiq_rec_cnt, new_msiq_rec_cnt;
+	msiqhead_t	new_head_index = msiq_p->msiq_curr_head_idx;
+	msiqhead_t	*curr_head_p;
+	msiqtail_t	curr_tail_index;
 	msgcode_t	msg_code;
 	px_ih_t		*ih_p;
 	int		i, ret;
+	ushort_t	msiq_recs2process;
 
 	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: msiq_id =%x ino=%x pil=%x "
 	    "ih_size=%x ih_lst=%x\n", msiq_p->msiq_id, ino_p->ino_ino,
 	    ino_p->ino_pil, ino_p->ino_ih_size, ino_p->ino_ih_head);
 
-	/* Read current MSIQ head index */
-	px_lib_msiq_gethead(dip, msiq_p->msiq_id, &curr_msiq_rec_cnt);
-	msiq_p->msiq_curr = (uint64_t)((caddr_t)msiq_p->msiq_base +
-	    curr_msiq_rec_cnt * sizeof (msiq_rec_t));
-	new_msiq_rec_cnt = curr_msiq_rec_cnt;
+	/* Read current MSIQ tail index */
+	px_lib_msiq_gettail(dip, msiq_p->msiq_id, &curr_tail_index);
 
-	/* Read next MSIQ record */
-	px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p);
+	if (curr_tail_index < new_head_index)
+		curr_tail_index += msiq_state_p->msiq_rec_cnt;
 
 	/*
-	 * Process current MSIQ record as long as record type
-	 * field is non-zero.
+	 * Calculate the number of recs to process by taking the difference
+	 * between the head and tail pointers. For all records we always
+	 * verify that we have a valid record type before we do any processing.
+	 * If triggered, we should always have at least 1 valid record.
 	 */
-	while (msiq_rec_p->msiq_rec_type) {
+	msiq_recs2process = curr_tail_index - new_head_index;
+
+	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: curr_head %x "
+	    "rec2process %x\n", new_head_index, msiq_recs2process);
+
+	curr_head_p = (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p +
+	    new_head_index * sizeof (msiq_rec_t));
+
+	for (i = 0; i < msiq_recs2process; i++) {
+		/* Read MSIQ record */
+		px_lib_get_msiq_rec(dip, curr_head_p, msiq_rec_p);
+
 		DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: MSIQ RECORD, "
 		    "msiq_rec_type 0x%llx msiq_rec_rid 0x%llx\n",
 		    msiq_rec_p->msiq_rec_type, msiq_rec_p->msiq_rec_rid);
 
-		/* Get the pointer next EQ record */
-		msiq_p->msiq_curr = (uint64_t)
-		    ((caddr_t)msiq_p->msiq_curr + sizeof (msiq_rec_t));
-
-		/* Check for overflow condition */
-		if (msiq_p->msiq_curr >= (uint64_t)((caddr_t)msiq_p->msiq_base +
-		    msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t)))
-			msiq_p->msiq_curr = msiq_p->msiq_base;
+		if (!msiq_rec_p->msiq_rec_type)
+			break;
 
 		/* Check MSIQ record type */
 		switch (msiq_rec_p->msiq_rec_type) {
@@ -343,34 +350,41 @@
 
 			DTRACE_PROBE4(interrupt__complete, dev_info_t, dip,
 			    void *, handler, caddr_t, arg1, int, ret);
+
+			new_head_index++;
 		} else {
 			DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr:"
-			    "Not found matching MSIQ record\n");
+			    "No matching MSIQ record found\n");
+		}
+next_rec:
+		/* Get the pointer next EQ record */
+		curr_head_p = (msiqhead_t *)
+		    ((caddr_t)curr_head_p + sizeof (msiq_rec_t));
 
-			/* px_spurintr(ino_p); */
-			ino_p->ino_unclaimed++;
-		}
-
-next_rec:
-		new_msiq_rec_cnt++;
+		/* Check for overflow condition */
+		if (curr_head_p >= (msiqhead_t *)((caddr_t)msiq_p->msiq_base_p
+		    + msiq_state_p->msiq_rec_cnt * sizeof (msiq_rec_t)))
+			curr_head_p = (msiqhead_t *)msiq_p->msiq_base_p;
 
 		/* Zero out msiq_rec_type field */
 		msiq_rec_p->msiq_rec_type = 0;
-
-		/* Read next MSIQ record */
-		px_lib_get_msiq_rec(dip, msiq_p, msiq_rec_p);
 	}
 
-	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: No of MSIQ recs processed %x\n",
-	    (new_msiq_rec_cnt - curr_msiq_rec_cnt));
+	DBG(DBG_MSIQ_INTR, dip, "px_msiq_intr: # of MSIQ recs processed %x\n",
+	    (new_head_index - msiq_p->msiq_curr_head_idx));
+
+	if (new_head_index <= msiq_p->msiq_curr_head_idx) {
+		if (px_unclaimed_intr_block) {
+			return (px_spurintr(ino_p));
+		}
+	}
 
 	/*  Update MSIQ head index with no of MSIQ records processed */
-	if (new_msiq_rec_cnt > curr_msiq_rec_cnt)  {
-		if (new_msiq_rec_cnt >= msiq_state_p->msiq_rec_cnt)
-			new_msiq_rec_cnt -= msiq_state_p->msiq_rec_cnt;
+	if (new_head_index >= msiq_state_p->msiq_rec_cnt)
+		new_head_index -= msiq_state_p->msiq_rec_cnt;
 
-		px_lib_msiq_sethead(dip, msiq_p->msiq_id, new_msiq_rec_cnt);
-	}
+	msiq_p->msiq_curr_head_idx = new_head_index;
+	px_lib_msiq_sethead(dip, msiq_p->msiq_id, new_head_index);
 
 	/* Clear the pending state */
 	if (px_lib_intr_setstate(dip, ino_p->ino_sysino,
--- a/usr/src/uts/sun4/io/px/px_lib.h	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px_lib.h	Mon Aug 21 21:16:28 2006 -0700
@@ -117,9 +117,8 @@
     msiqhead_t msiq_head);
 extern int px_lib_msiq_gettail(dev_info_t *dip, msiqid_t msiq_id,
     msiqtail_t *msiq_tail);
-extern void px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p,
+extern void px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
     msiq_rec_t *msiq_rec_p);
-
 /*
  * MSI Functions:
  */
--- a/usr/src/uts/sun4/io/px/px_msiq.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px_msiq.c	Mon Aug 21 21:16:28 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -95,10 +94,8 @@
 		    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 = (uint64_t)
+		msiq_state_p->msiq_p[i].msiq_base_p = (msiqhead_t *)
 		    ((caddr_t)msiq_addr + (i * msiq_size));
-		msiq_state_p->msiq_p[i].msiq_curr =
-		    msiq_state_p->msiq_p[i].msiq_base;
 	}
 
 	if ((ret = px_lib_msiq_init(px_p->px_dip)) != DDI_SUCCESS)
@@ -129,6 +126,20 @@
 }
 
 /*
+ * px_msiq_resume()
+ */
+void
+px_msiq_resume(px_t *px_p)
+{
+	px_msiq_state_t *msiq_state_p = &px_p->px_ib_p->ib_msiq_state;
+	int		i;
+
+	for (i = 0; i < msiq_state_p->msiq_cnt; i++)
+		(void) px_lib_msiq_gethead(px_p->px_dip, i,
+		    &msiq_state_p->msiq_p[i].msiq_curr_head_idx);
+}
+
+/*
  * px_msiq_alloc()
  */
 int
@@ -196,9 +207,8 @@
 
 	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_curr =
-			    msiq_state_p->msiq_p[i].msiq_base;
 			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/sun4/io/px/px_msiq.h	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4/io/px/px_msiq.h	Mon Aug 21 21:16:28 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,8 +38,8 @@
 struct px_msiq {
 	msiqid_t	msiq_id;	/* MSIQ ID */
 	uint_t		msiq_state;	/* MSIQ alloc state */
-	msiqhead_t	msiq_base;	/* MSIQ base pointer */
-	msiqtail_t	msiq_curr;	/* MSIQ Curr pointer */
+	msiqhead_t	msiq_curr_head_idx; /* MSIQ current head */
+	msiqhead_t	*msiq_base_p;	/* MSIQ base pointer */
 };
 
 #define	MSIQ_STATE_FREE		0x1
@@ -90,6 +89,7 @@
 
 extern	int	px_msiq_attach(px_t *px_p);
 extern	void	px_msiq_detach(px_t *px_p);
+extern	void	px_msiq_resume(px_t *px_p);
 
 extern	int	px_msiq_alloc(px_t *px_p, msiq_rec_type_t rec_type,
 		    msiqid_t *msiq_id_p);
--- a/usr/src/uts/sun4u/io/px/px_lib4u.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4u/io/px/px_lib4u.c	Mon Aug 21 21:16:28 2006 -0700
@@ -922,9 +922,10 @@
 
 /*ARGSUSED*/
 void
-px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p, msiq_rec_t *msiq_rec_p)
+px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
+    msiq_rec_t *msiq_rec_p)
 {
-	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_p->msiq_curr;
+	eq_rec_t	*eq_rec_p = (eq_rec_t *)msiq_head_p;
 
 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p eq_rec_p 0x%p\n",
 	    dip, eq_rec_p);
--- a/usr/src/uts/sun4v/io/px/px_lib4v.c	Mon Aug 21 20:11:18 2006 -0700
+++ b/usr/src/uts/sun4v/io/px/px_lib4v.c	Mon Aug 21 21:16:28 2006 -0700
@@ -777,9 +777,10 @@
 
 /*ARGSUSED*/
 void
-px_lib_get_msiq_rec(dev_info_t *dip, px_msiq_t *msiq_p, msiq_rec_t *msiq_rec_p)
+px_lib_get_msiq_rec(dev_info_t *dip, msiqhead_t *msiq_head_p,
+    msiq_rec_t *msiq_rec_p)
 {
-	msiq_rec_t	*curr_msiq_rec_p = (msiq_rec_t *)msiq_p->msiq_curr;
+	msiq_rec_t	*curr_msiq_rec_p = (msiq_rec_t *)msiq_head_p;
 
 	DBG(DBG_LIB_MSIQ, dip, "px_lib_get_msiq_rec: dip 0x%p\n", dip);