Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/mips/alchemy Add au_intr_enable() and au_intr_disab...



details:   https://anonhg.NetBSD.org/src/rev/fdfd038b6793
branches:  trunk
changeset: 588158:fdfd038b6793
user:      gdamore <gdamore%NetBSD.org@localhost>
date:      Fri Feb 10 00:22:42 2006 +0000

description:
Add au_intr_enable() and au_intr_disable() API to allow for split interrupts
(e.g. PCMCIA leaves GPIO interrupt masked and reenables them soft interrupt.)
Add checks for masked interrupts before calling the handler.
When removing last interrupt handler, mask off interrupts completely using
MASK_CLEAR and WAKEUP_CLEAR.  Tested on dbau1500.

diffstat:

 sys/arch/mips/alchemy/au_icu.c        |  71 +++++++++++++++++++++++++++++-----
 sys/arch/mips/alchemy/include/auvar.h |   4 +-
 2 files changed, 62 insertions(+), 13 deletions(-)

diffs (144 lines):

diff -r c63d1ae7f1c6 -r fdfd038b6793 sys/arch/mips/alchemy/au_icu.c
--- a/sys/arch/mips/alchemy/au_icu.c    Thu Feb 09 23:36:48 2006 +0000
+++ b/sys/arch/mips/alchemy/au_icu.c    Fri Feb 10 00:22:42 2006 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: au_icu.c,v 1.14 2006/02/09 18:03:12 gdamore Exp $      */
+/*     $NetBSD: au_icu.c,v 1.15 2006/02/10 00:22:42 gdamore Exp $      */
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -75,7 +75,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.14 2006/02/09 18:03:12 gdamore Exp $");
+__KERNEL_RCSID(0, "$NetBSD: au_icu.c,v 1.15 2006/02/10 00:22:42 gdamore Exp $");
 
 #include "opt_ddb.h"
 
@@ -316,7 +316,9 @@
                REGVAL(icu_base + IC_CONFIG1_CLEAR) = irq;
                REGVAL(icu_base + IC_CONFIG0_CLEAR) = irq;
 
-               /* XXX disable with MASK_CLEAR and WAKEUP_CLEAR */
+               /* disable with MASK_CLEAR and WAKEUP_CLEAR */
+               REGVAL(icu_base + IC_MASK_CLEAR) = irq;
+               REGVAL(icu_base + IC_WAKEUP_CLEAR) = irq;
        }
 
        splx(s);
@@ -329,7 +331,7 @@
 {
        struct au_intrhand *ih;
        int level;
-       uint32_t icu_base = 0, irqmask = 0;     /* Both XXX gcc */
+       uint32_t icu_base = 0, irqstat = 0, irqmask = 0; /* XXX gcc */
 
        for (level = 3; level >= 0; level--) {
                if ((ipending & (MIPS_INT_MASK_0 << level)) == 0)
@@ -351,30 +353,32 @@
                switch (level) {
                case 0:
                        icu_base = ic0_base;
-                       irqmask = REGVAL(icu_base + IC_REQUEST0_INT);
+                       irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
                        break;
                case 1:
                        icu_base = ic0_base;
-                       irqmask = REGVAL(icu_base + IC_REQUEST1_INT);
+                       irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
                        break;
                case 2:
                        icu_base = ic1_base;
-                       irqmask = REGVAL(icu_base + IC_REQUEST0_INT);
+                       irqstat = REGVAL(icu_base + IC_REQUEST0_INT);
                        break;
                case 3:
                        icu_base = ic1_base;
-                       irqmask = REGVAL(icu_base + IC_REQUEST1_INT);
+                       irqstat = REGVAL(icu_base + IC_REQUEST1_INT);
                        break;
                }
+               irqmask = REGVAL(icu_base + IC_MASK_READ);
                au_cpuintrs[level].cintr_count.ev_count++;
                LIST_FOREACH(ih, &au_cpuintrs[level].cintr_list, ih_q) {
-                       /* XXX should check is see if interrupt is masked? */
-                       if (1 << ih->ih_irq & irqmask) {
+                       int irq = (1 << ih->ih_irq);
+
+                       if ((irq && irqmask) && (irq && irqstat)) {
                                au_icu_intrtab[ih->ih_irq].intr_count.ev_count++;
                                (*ih->ih_func)(ih->ih_arg);
 
-                               REGVAL(icu_base + IC_MASK_CLEAR) = 1 << ih->ih_irq;
-                               REGVAL(icu_base + IC_MASK_SET) = 1 << ih->ih_irq;
+                               REGVAL(icu_base + IC_MASK_CLEAR) = irq;
+                               REGVAL(icu_base + IC_MASK_SET) = irq;
                        }
                }
                cause &= ~(MIPS_INT_MASK_0 << level);
@@ -383,3 +387,46 @@
        /* Re-enable anything that we have processed. */
        _splset(MIPS_SR_INT_IE | ((status & ~cause) & MIPS_HARD_INT_MASK));
 }
+
+/*
+ * Some devices (e.g. PCMCIA) want to be able to mask interrupts at
+ * the ICU, and leave them masked off until some later time
+ * (e.g. reenabled by a soft interrupt).
+ */
+
+void
+au_intr_enable(int irq)
+{
+       int             s;
+       uint32_t        icu_base, mask;
+
+       if (irq >= NIRQS)
+               panic("au_intr_enable: bogus IRQ %d", irq);
+
+       icu_base = (irq < 32) ? ic0_base : ic1_base;
+       mask = irq & 31;
+       mask = 1 << mask;
+
+       s = splhigh();
+       /* only enable the interrupt if we have a handler */
+       if (au_icu_intrtab[irq].intr_refcnt)
+               REGVAL(icu_base + IC_MASK_SET) = mask;
+       splx(s);
+}
+
+void
+au_intr_disable(int irq)
+{
+       int             s;
+       uint32_t        icu_base, mask;
+
+       icu_base = (irq < 32) ? ic0_base : ic1_base;
+       mask = irq & 31;
+       mask = 1 << mask;
+
+       if (irq >= NIRQS)
+               panic("au_intr_disable: bogus IRQ %d", irq);
+       s = splhigh();
+       REGVAL(icu_base + IC_MASK_CLEAR) = mask;
+       splx(s);
+}
diff -r c63d1ae7f1c6 -r fdfd038b6793 sys/arch/mips/alchemy/include/auvar.h
--- a/sys/arch/mips/alchemy/include/auvar.h     Thu Feb 09 23:36:48 2006 +0000
+++ b/sys/arch/mips/alchemy/include/auvar.h     Fri Feb 10 00:22:42 2006 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: auvar.h,v 1.5 2006/02/09 00:26:40 gdamore Exp $ */
+/* $NetBSD: auvar.h,v 1.6 2006/02/10 00:22:42 gdamore Exp $ */
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -122,6 +122,8 @@
 void   au_intr_init(void);
 void   *au_intr_establish(int, int, int, int, int (*)(void *), void *);
 void   au_intr_disestablish(void *);
+void   au_intr_enable(int);
+void   au_intr_disable(int);
 void   au_iointr(u_int32_t, u_int32_t, u_int32_t, u_int32_t);
 
 void   au_cpureg_bus_mem_init(bus_space_tag_t, void *);



Home | Main Index | Thread Index | Old Index