Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Dec 2009 17:42:40 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r200517 - stable/8/sys/dev/puc
Message-ID:  <200912141742.nBEHgeFZ033132@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Mon Dec 14 17:42:40 2009
New Revision: 200517
URL: http://svn.freebsd.org/changeset/base/200517

Log:
  MFC rev 200397:
  Fix interrupt handling.
  
  PR:		kern/140947

Modified:
  stable/8/sys/dev/puc/puc.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/puc/puc.c
==============================================================================
--- stable/8/sys/dev/puc/puc.c	Mon Dec 14 17:04:44 2009	(r200516)
+++ stable/8/sys/dev/puc/puc.c	Mon Dec 14 17:42:40 2009	(r200517)
@@ -129,62 +129,78 @@ puc_intr(void *arg)
 {
 	struct puc_port *port;
 	struct puc_softc *sc = arg;
-	u_long dev, devs;
-	int i, idx, ipend, isrc;
+	u_long ds, dev, devs;
+	int i, idx, ipend, isrc, nints;
 	uint8_t ilr;
 
-	devs = sc->sc_serdevs;
-	if (sc->sc_ilr == PUC_ILR_DIGI) {
-		idx = 0;
-		while (devs & (0xfful << idx)) {
-			ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
-			devs &= ~0ul ^ ((u_long)ilr << idx);
-			idx += 8;
-		}
-	} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
+	nints = 0;
+	while (1) {
 		/*
-		 * Don't trust the value if it's the same as the option
-		 * register. It may mean that the ILR is not active and
-		 * we're reading the option register instead. This may
-		 * lead to false positives on 8-port boards.
+		 * Obtain the set of devices with pending interrupts.
 		 */
-		ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
-		if (ilr != (sc->sc_cfg_data & 0xff))
-			devs &= (u_long)ilr;
-	}
-
-	ipend = 0;
-	idx = 0, dev = 1UL;
-	while (devs != 0UL) {
-		while ((devs & dev) == 0UL)
-			idx++, dev <<= 1;
-		devs &= ~dev;
-		port = &sc->sc_port[idx];
-		port->p_ipend = SERDEV_IPEND(port->p_dev);
-		ipend |= port->p_ipend;
-	}
+		devs = sc->sc_serdevs;
+		if (sc->sc_ilr == PUC_ILR_DIGI) {
+			idx = 0;
+			while (devs & (0xfful << idx)) {
+				ilr = ~bus_read_1(sc->sc_port[idx].p_rres, 7);
+				devs &= ~0ul ^ ((u_long)ilr << idx);
+				idx += 8;
+			}
+		} else if (sc->sc_ilr == PUC_ILR_QUATECH) {
+			/*
+			 * Don't trust the value if it's the same as the option
+			 * register. It may mean that the ILR is not active and
+			 * we're reading the option register instead. This may
+			 * lead to false positives on 8-port boards.
+			 */
+			ilr = bus_read_1(sc->sc_port[0].p_rres, 7);
+			if (ilr != (sc->sc_cfg_data & 0xff))
+				devs &= (u_long)ilr;
+		}
+		if (devs == 0UL)
+			break;
 
-	i = 0, isrc = SER_INT_OVERRUN;
-	while (ipend) {
-		while (i < PUC_ISRCCNT && !(ipend & isrc))
-			i++, isrc <<= 1;
-		KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
-		ipend &= ~isrc;
+		/*
+		 * Obtain the set of interrupt sources from those devices
+		 * that have pending interrupts.
+		 */
+		ipend = 0;
 		idx = 0, dev = 1UL;
-		devs = sc->sc_serdevs;
-		while (devs != 0UL) {
-			while ((devs & dev) == 0UL)
+		ds = devs;
+		while (ds != 0UL) {
+			while ((ds & dev) == 0UL)
 				idx++, dev <<= 1;
-			devs &= ~dev;
+			ds &= ~dev;
 			port = &sc->sc_port[idx];
-			if (!(port->p_ipend & isrc))
-				continue;
-			if (port->p_ihsrc[i] != NULL)
-				(*port->p_ihsrc[i])(port->p_iharg);
+			port->p_ipend = SERDEV_IPEND(port->p_dev);
+			ipend |= port->p_ipend;
+		}
+		if (ipend == 0)
+			break;
+
+		i = 0, isrc = SER_INT_OVERRUN;
+		while (ipend) {
+			while (i < PUC_ISRCCNT && !(ipend & isrc))
+				i++, isrc <<= 1;
+			KASSERT(i < PUC_ISRCCNT, ("%s", __func__));
+			ipend &= ~isrc;
+			idx = 0, dev = 1UL;
+			ds = devs;
+			while (ds != 0UL) {
+				while ((ds & dev) == 0UL)
+					idx++, dev <<= 1;
+				ds &= ~dev;
+				port = &sc->sc_port[idx];
+				if (!(port->p_ipend & isrc))
+					continue;
+				if (port->p_ihsrc[i] != NULL)
+					(*port->p_ihsrc[i])(port->p_iharg);
+				nints++;
+			}
 		}
-		return (FILTER_HANDLED);
 	}
-	return (FILTER_STRAY);
+
+	return ((nints > 0) ? FILTER_HANDLED : FILTER_STRAY);
 }
 
 int



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912141742.nBEHgeFZ033132>