Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/sparc/dev Establish interrupt handlers with proper ...



details:   https://anonhg.NetBSD.org/src/rev/140165ece9c5
branches:  trunk
changeset: 755867:140165ece9c5
user:      tsutsui <tsutsui%NetBSD.org@localhost>
date:      Sat Jun 26 01:42:57 2010 +0000

description:
Establish interrupt handlers with proper softc per each zs device
rather than sharing them among all zs devices and searching softc
in handlers.

The latter method is derived from ancient sun3 zs driver which tried
to reduce overhead on autovectored interrupts, but nowadays such hack
might cause recursive global locks on modern SMP capable framework.

Fixes "5.99.30 sparc panic during startup" reported by Hauke Fath
on tech-kern@:
http://mail-index.NetBSD.org/tech-kern/2010/06/19/msg008374.html
and also tested by Jochen Kunz on SS20 with both serial and kbd console.

Ok'ed by mrg@ and dyoung@.

diffstat:

 sys/arch/sparc/dev/zs.c |  110 +++++++++--------------------------------------
 1 files changed, 22 insertions(+), 88 deletions(-)

diffs (172 lines):

diff -r 4055acbf0d26 -r 140165ece9c5 sys/arch/sparc/dev/zs.c
--- a/sys/arch/sparc/dev/zs.c   Sat Jun 26 00:25:02 2010 +0000
+++ b/sys/arch/sparc/dev/zs.c   Sat Jun 26 01:42:57 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: zs.c,v 1.118 2010/06/04 06:04:15 macallan Exp $        */
+/*     $NetBSD: zs.c,v 1.119 2010/06/26 01:42:57 tsutsui Exp $ */
 
 /*-
  * Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.118 2010/06/04 06:04:15 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: zs.c,v 1.119 2010/06/26 01:42:57 tsutsui Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -171,12 +171,8 @@
 
 extern struct cfdriver zs_cd;
 
-/* softintr(9) cookie, shared by all instances of this driver */
-static void *zs_sicookie;
-
 /* Interrupt handlers. */
 static int zshard(void *);
-static void zssoft(void *);
 
 static int zs_get_speed(struct zs_chanstate *);
 
@@ -396,7 +392,6 @@
        struct zsc_attach_args zsc_args;
        struct zs_chanstate *cs;
        int channel;
-       static int didintr, prevpri;
 #if (NKBD > 0) || (NMS > 0)
        int ch0_is_cons = 0;
 #endif
@@ -407,12 +402,11 @@
                return;
        }
 
-       if (!didintr) {
-               zs_sicookie = softint_establish(SOFTINT_SERIAL, zssoft, NULL);
-               if (zs_sicookie == NULL) {
-                       aprint_error(": cannot establish soft int handler\n");
-                       return;
-               }
+       zsc->zsc_sicookie = softint_establish(SOFTINT_SERIAL,
+           (void (*)(void *))zsc_intr_soft, zsc);
+       if (zsc->zsc_sicookie == NULL) {
+               aprint_error(": cannot establish soft int handler\n");
+               return;
        }
        aprint_normal(" softpri %d\n", IPL_SOFTSERIAL);
 
@@ -566,17 +560,9 @@
        }
 
        /*
-        * Now safe to install interrupt handlers.  Note the arguments
-        * to the interrupt handlers aren't used.  Note, we only do this
-        * once since both SCCs interrupt at the same level and vector.
+        * Now safe to install interrupt handlers.
         */
-       if (!didintr) {
-               didintr = 1;
-               prevpri = pri;
-               bus_intr_establish(zsc->zsc_bustag, pri, IPL_SERIAL,
-                                  zshard, NULL);
-       } else if (pri != prevpri)
-               panic("broken zs interrupt scheme");
+       bus_intr_establish(zsc->zsc_bustag, pri, IPL_SERIAL, zshard, zsc);
 
        evcnt_attach_dynamic(&zsc->zsc_intrcnt, EVCNT_TYPE_INTR, NULL,
            device_xname(zsc->zsc_dev), "intr");
@@ -625,81 +611,29 @@
 static volatile int zssoftpending;
 
 /*
- * Our ZS chips all share a common, autovectored interrupt,
- * so we have to look at all of them on each interrupt.
+ * Our ZS chips all share a common interrupt level,
+ * but we establish zshard handler per each ZS chips
+ * to avoid holding unnecessary locks in interrupt context.
  */
 static int
 zshard(void *arg)
 {
-       struct zsc_softc *zsc;
-       int unit, rr3, rval, softreq;
-
-       rval = softreq = 0;
-       for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
-               struct zs_chanstate *cs;
+       struct zsc_softc *zsc = arg;
+       int rr3, rval;
 
-               zsc = device_lookup_private(&zs_cd, unit);
-               if (zsc == NULL)
-                       continue;
-               rr3 = zsc_intr_hard(zsc);
-               /* Count up the interrupts. */
-               if (rr3) {
-                       rval |= rr3;
-                       zsc->zsc_intrcnt.ev_count++;
-               }
-               if ((cs = zsc->zsc_cs[0]) != NULL)
-                       softreq |= cs->cs_softreq;
-               if ((cs = zsc->zsc_cs[1]) != NULL)
-                       softreq |= cs->cs_softreq;
+       rval = 0;
+       rr3 = zsc_intr_hard(zsc);
+       /* Count up the interrupts. */
+       if (rr3) {
+               rval = rr3;
+               zsc->zsc_intrcnt.ev_count++;
        }
-
-       /* We are at splzs here, so no need to lock. */
-       if (softreq && (zssoftpending == 0)) {
-               zssoftpending = 1;
-               softint_schedule(zs_sicookie);
-       }
+       if (zsc->zsc_cs[0]->cs_softreq || zsc->zsc_cs[1]->cs_softreq)
+               softint_schedule(zsc->zsc_sicookie);
        return (rval);
 }
 
 /*
- * Similar scheme as for zshard (look at all of them)
- */
-static void
-zssoft(void *arg)
-{
-       struct zsc_softc *zsc;
-       int unit;
-
-       /* This is not the only ISR on this IPL. */
-       if (zssoftpending == 0)
-               return;
-
-       /*
-        * The soft intr. bit will be set by zshard only if
-        * the variable zssoftpending is zero.  The order of
-        * these next two statements prevents our clearing
-        * the soft intr bit just after zshard has set it.
-        */
-       /* ienab_bic(IE_ZSSOFT); */
-       zssoftpending = 0;
-
-#if 0 /* not yet */
-       /* Make sure we call the tty layer with tty_lock held. */
-       mutex_spin_enter(&tty_lock);
-#endif
-       for (unit = 0; unit < zs_cd.cd_ndevs; unit++) {
-               zsc = device_lookup_private(&zs_cd, unit);
-               if (zsc == NULL)
-                       continue;
-               (void)zsc_intr_soft(zsc);
-       }
-#if 0 /* not yet */
-       mutex_spin_exit(&tty_lock);
-#endif
-}
-
-
-/*
  * Compute the current baud rate given a ZS channel.
  */
 static int



Home | Main Index | Thread Index | Old Index