summaryrefslogtreecommitdiff
path: root/sys/arch/arm/xscale/i80321_intr.c
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2006-06-15 21:35:31 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2006-06-15 21:35:31 +0000
commiteb72c88524d7fac5c9a2ccb8306990a74581b569 (patch)
treeb058d1608e53e69a7360eb5c4200d3f52b305e56 /sys/arch/arm/xscale/i80321_intr.c
parente14575985cf7a5cf6a4769c170aa0467b191db28 (diff)
rewritten, simplifed interrupt controller for 80321, half the lines
and much less complex. IPL_SERIAL goes at the same time.
Diffstat (limited to 'sys/arch/arm/xscale/i80321_intr.c')
-rw-r--r--sys/arch/arm/xscale/i80321_intr.c673
1 files changed, 189 insertions, 484 deletions
diff --git a/sys/arch/arm/xscale/i80321_intr.c b/sys/arch/arm/xscale/i80321_intr.c
index e64850b34d1..77a84ddb2b5 100644
--- a/sys/arch/arm/xscale/i80321_intr.c
+++ b/sys/arch/arm/xscale/i80321_intr.c
@@ -1,45 +1,19 @@
-/* $OpenBSD: i80321_intr.c,v 1.4 2006/06/01 17:33:47 drahn Exp $ */
-/* $NetBSD: i80321_icu.c,v 1.11 2005/12/24 20:06:52 perry Exp $ */
+/* $OpenBSD: i80321_intr.c,v 1.5 2006/06/15 21:35:30 drahn Exp $ */
/*
- * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
- * All rights reserved.
+ * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
*
- * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed for the NetBSD Project by
- * Wasabi Systems, Inc.
- * 4. The name of Wasabi Systems, Inc. may not be used to endorse
- * or promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-
-/*
- * Interrupt support for the Intel i80321 I/O Processor.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
@@ -47,407 +21,209 @@
#include <sys/malloc.h>
#include <sys/evcount.h>
-#include <uvm/uvm_extern.h>
-
-#include <machine/bus.h>
#include <machine/intr.h>
#include <arm/cpufunc.h>
-
#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>
-/* Interrupt handler queues. */
-struct intrq intrq[NIRQ];
-
-/* Interrupts to mask at each level. */
-int i80321_imask[NIPL];
-
-/* Current interrupt priority level. */
-volatile int current_ipl_level;
-
-/* Interrupts pending. */
-volatile int i80321_ipending;
-volatile int softint_ipending;
-
-/* Software copy of the IRQs we have enabled. */
-volatile uint32_t intr_enabled;
-
-/* Mask if interrupts steered to FIQs. */
-uint32_t intr_steer;
-
-#define INT_SWMASK \
- ((1U << ICU_INT_bit23) | (1U << ICU_INT_bit22) | \
- (1U << ICU_INT_bit5) | (1U << ICU_INT_bit4))
/*
- * Map a software interrupt queue index (to the unused bits in the
- * ICU registers -- XXX will need to revisit this if those bits are
- * ever used in future steppings).
+ * autoconf glue
*/
-static const uint32_t si_to_irqbit[SI_NQUEUES] = {
- ICU_INT_bit23, /* SI_SOFT */
- ICU_INT_bit22, /* SI_SOFTCLOCK */
- ICU_INT_bit5, /* SI_SOFTNET */
- ICU_INT_bit4, /* SI_SOFTSERIAL */
-};
+int i80321intc_match(struct device *, void *, void *);
+void i80321intc_attach(struct device *, struct device *, void *);
-#define SI_TO_IRQBIT(si) (1U << si_to_irqbit[(si)])
+/* internal functions */
+void i80321intc_write_intctl(uint32_t mask);
+void i80321intc_write_steer(uint32_t mask);
+uint32_t i80321intc_read_intsrc(void);
+void i80321intc_calc_mask(void);
+void i80321intc_init(void);
+void i80321intc_intr_init(void);
+void i80321intc_setipl(int new);
+void i80321intc_do_pending(void);
-/*
- * Map a software interrupt queue to an interrupt priority level.
- */
-static const int si_to_ipl[SI_NQUEUES] = {
- IPL_SOFT, /* SI_SOFT */
- IPL_SOFTCLOCK, /* SI_SOFTCLOCK */
- IPL_SOFTNET, /* SI_SOFTNET */
- IPL_SOFTSERIAL, /* SI_SOFTSERIAL */
-};
+uint32_t i80321intc_imask[NIPL];
+uint32_t i80321intc_smask[NIPL];
-/*
- * Interrupt bit names.
- */
-const char *i80321_irqnames[] = {
- "DMA0 EOT",
- "DMA0 EOC",
- "DMA1 EOT",
- "DMA1 EOC",
- "irq 4",
- "irq 5",
- "AAU EOT",
- "AAU EOC",
- "core PMU",
- "TMR0 (hardclock)",
- "TMR1",
- "I2C0",
- "I2C1",
- "MU",
- "BIST",
- "periph PMU",
- "XScale PMU",
- "BIU error",
- "ATU error",
- "MCU error",
- "DMA0 error",
- "DMA1 error",
- "irq 22",
- "AAU error",
- "MU error",
- "SSP",
- "irq 26",
- "irq 27",
- "irq 28",
- "irq 29",
- "irq 30",
- "irq 31",
-};
-
-int i80321intc_match(struct device *parent, void *cf, void *aux);
-void i80321intc_attach(struct device *, struct device *, void *);
-void i80321_set_intrmask(void);
-void i80321_do_pending(void);
-uint32_t i80321_iintsrc_read(void);
-void i80321_enable_irq(int irq);
-void i80321_disable_irq(int irq);
-void i80321_intr_calculate_masks(void);
+#define SI_TO_IRQBIT(x) (1 << (x))
+__volatile int current_ipl_level;
+__volatile int softint_pending;
struct cfattach i80321intc_ca = {
sizeof(struct device), i80321intc_match, i80321intc_attach
};
-
+
struct cfdriver i80321intc_cd = {
NULL, "i80321intc", DV_DULL
};
+int i80321intc_attached = 0;
+
int
-i80321intc_match(struct device *parent, void *cf, void *aux)
+i80321intc_match(struct device *parent, void *v, void *aux)
{
-
- /* XXX */
-#if 0
- struct ip_attach_args *pxa = aux;
+ if (i80321intc_attached == 0)
+ return 1;
- if (pxaintc_attached || pxa->pxa_addr != PXA2X0_INTCTL_BASE)
- return (0);
-#endif
-
- return (1);
+ i80321intc_attached = 1;
+ return 0;
}
+
void
i80321intc_attach(struct device *parent, struct device *self, void *args)
{
- i80321_icu_init();
+ i80321intc_init();
}
-void
-i80321_set_intrmask(void)
+void
+i80321intc_write_intctl(uint32_t mask)
{
- extern volatile uint32_t intr_enabled;
-
- __asm volatile("mcr p6, 0, %0, c0, c0, 0"
- :
- : "r" (intr_enabled & ICU_INT_HWMASK));
+ __asm__ volatile ("mcr p6, 0, %0, c0, c0, 0" : : "r" (mask));
}
-
-void i80321_intr_dispatch(struct clockframe *frame);
-
-uint32_t
-i80321_iintsrc_read(void)
+void
+i80321intc_write_steer(uint32_t mask)
{
- uint32_t iintsrc;
-
- __asm volatile("mrc p6, 0, %0, c8, c0, 0"
- : "=r" (iintsrc));
-
- /*
- * The IINTSRC register shows bits that are active even
- * if they are masked in INTCTL, so we have to mask them
- * off with the interrupts we consider enabled.
- */
- return (iintsrc & intr_enabled);
+ __asm__ volatile ("mcr p6, 0, %0, c4, c0, 0" : : "r" (mask));
}
-static inline void
-i80321_set_intrsteer(void)
+uint32_t
+i80321intc_read_intsrc(void)
{
-
- __asm volatile("mcr p6, 0, %0, c4, c0, 0"
- :
- : "r" (intr_steer & ICU_INT_HWMASK));
+ uint32_t mask;
+ __asm__ volatile ("mrc p6, 0, %0, c8, c0, 0" : "=r" (mask));
+ return mask;
}
void
-i80321_enable_irq(int irq)
+i80321intc_setipl(int new)
{
-
- intr_enabled |= (1U << irq);
- i80321_set_intrmask();
+ current_ipl_level = new;
+ i80321intc_write_intctl(i80321intc_imask[new]);
}
-void
-i80321_disable_irq(int irq)
-{
- intr_enabled &= ~(1U << irq);
- i80321_set_intrmask();
-}
+struct intrq i80321_handler[NIRQ];
-/*
- * NOTE: This routine must be called with interrupts disabled in the CPSR.
- */
void
-i80321_intr_calculate_masks(void)
+i80321intc_calc_mask(void)
{
- struct intrq *iq;
+ int irq;
struct intrhand *ih;
- int irq, ipl;
+ int i;
- /* First, figure out which IPLs each IRQ has. */
for (irq = 0; irq < NIRQ; irq++) {
- int levels = 0;
- iq = &intrq[irq];
- i80321_disable_irq(irq);
- for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
- ih = TAILQ_NEXT(ih, ih_list))
- levels |= (1U << ih->ih_ipl);
- iq->iq_levels = levels;
- }
-
- /* Next, figure out which IRQs are used by each IPL. */
- for (ipl = 0; ipl < NIPL; ipl++) {
- int irqs = 0;
- for (irq = 0; irq < NIRQ; irq++) {
- if (intrq[irq].iq_levels & (1U << ipl))
- irqs |= (1U << irq);
+ int i;
+ int max = IPL_NONE;
+ int min = IPL_HIGH;
+ TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
+ if (ih->ih_ipl > max)
+ max = ih->ih_ipl;
+
+ if (ih->ih_ipl < min)
+ min = ih->ih_ipl;
}
- i80321_imask[ipl] = irqs;
- }
- i80321_imask[IPL_NONE] = 0;
-
- /*
- * Initialize the soft interrupt masks to block themselves.
- */
- i80321_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFT);
- i80321_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK);
- i80321_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET);
- i80321_imask[IPL_SOFTSERIAL] = SI_TO_IRQBIT(SI_SOFTSERIAL);
-
- /*
- * splsoftclock() is the only interface that users of the
- * generic software interrupt facility have to block their
- * soft intrs, so splsoftclock() must also block IPL_SOFT.
- */
- i80321_imask[IPL_SOFTCLOCK] |= i80321_imask[IPL_SOFT];
-
- /*
- * splsoftnet() must also block splsoftclock(), since we don't
- * want timer-driven network events to occur while we're
- * processing incoming packets.
- */
- i80321_imask[IPL_SOFTNET] |= i80321_imask[IPL_SOFTCLOCK];
-
- /*
- * Enforce a heirarchy that gives "slow" device (or devices with
- * limited input buffer space/"real-time" requirements) a better
- * chance at not dropping data.
- */
- i80321_imask[IPL_BIO] |= i80321_imask[IPL_SOFTNET];
- i80321_imask[IPL_NET] |= i80321_imask[IPL_BIO];
- i80321_imask[IPL_SOFTSERIAL] |= i80321_imask[IPL_NET];
- i80321_imask[IPL_TTY] |= i80321_imask[IPL_SOFTSERIAL];
-
- /*
- * splvm() blocks all interrupts that use the kernel memory
- * allocation facilities.
- */
- i80321_imask[IPL_VM] |= i80321_imask[IPL_TTY];
-
- /*
- * Audio devices are not allowed to perform memory allocation
- * in their interrupt routines, and they have fairly "real-time"
- * requirements, so give them a high interrupt priority.
- */
- i80321_imask[IPL_AUDIO] |= i80321_imask[IPL_VM];
-
- /*
- * splclock() must block anything that uses the scheduler.
- */
- i80321_imask[IPL_CLOCK] |= i80321_imask[IPL_AUDIO];
-
- /*
- * No separate statclock on the IQ80310.
- */
- i80321_imask[IPL_STATCLOCK] |= i80321_imask[IPL_CLOCK];
-
- /*
- * splhigh() must block "everything".
- */
- i80321_imask[IPL_HIGH] |= i80321_imask[IPL_STATCLOCK];
-
- /*
- * XXX We need serial drivers to run at the absolute highest priority
- * in order to avoid overruns, so serial > high.
- */
- i80321_imask[IPL_SERIAL] |= i80321_imask[IPL_HIGH];
-
- /*
- * Now compute which IRQs must be blocked when servicing any
- * given IRQ.
- */
- for (irq = 0; irq < NIRQ; irq++) {
- int maxirq = IPL_NONE;
- iq = &intrq[irq];
- if (TAILQ_FIRST(&iq->iq_list) != NULL)
- i80321_enable_irq(irq);
- for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
- ih = TAILQ_NEXT(ih, ih_list))
- maxirq = ih->ih_ipl > maxirq ? ih->ih_ipl : maxirq;
- iq->iq_irq = maxirq;
+ i80321_handler[irq].iq_irq = max;
+
+ if (max == IPL_NONE)
+ min = IPL_NONE;
+#if 0
+ printf("irq %d: min %x max %x\n", irq, min, max);
+#endif
+
+ /* Enable interrupts at lower levels */
+ for (i = 0; i < min; i++)
+ i80321intc_imask[i] |= (1 << irq);
+ /* Diable interrupts at upper levels */
+ for (;i <= IPL_HIGH; i++)
+ i80321intc_imask[i] &= ~(1 << irq);
+ }
+ /* initialize soft interrupt mask */
+ for (i = IPL_NONE; i < IPL_HIGH; i++) {
+ i80321intc_smask[i] = 0;
+ if (i < IPL_SOFT)
+ i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
+ if (i < IPL_SOFTCLOCK)
+ i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
+ if (i < IPL_SOFTNET)
+ i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
+ if (i < IPL_SOFTSERIAL)
+ i80321intc_smask[i] |= SI_TO_IRQBIT(SI_SOFTSERIAL);
+#if 0
+ printf("mask[%d]: %x %x\n", i, i80321intc_smask[i],
+ i80321intc_imask[i]);
+#endif
}
+
+ i80321intc_setipl(current_ipl_level);
}
void
-i80321_do_pending(void)
+i80321intc_do_pending(void)
{
static int processing = 0;
- int new, oldirqstate;
+ int oldirqstate, spl_save;
oldirqstate = disable_interrupts(I32_bit);
- if (processing) {
+ spl_save = current_ipl_level;
+
+ if (processing == 1) {
restore_interrupts(oldirqstate);
return;
}
- processing = 1;
-
- new = current_ipl_level;
-
-
-#define DO_SOFTINT(si) \
- if ((softint_ipending & ~i80321_imask[new]) & SI_TO_IRQBIT(si)){ \
- softint_ipending &= ~SI_TO_IRQBIT(si); \
- current_ipl_level = si_to_ipl[(si)]; \
+#define DO_SOFTINT(si, ipl) \
+ if ((softint_pending & i80321intc_smask[current_ipl_level]) & \
+ SI_TO_IRQBIT(si)) { \
+ softint_pending &= ~SI_TO_IRQBIT(si); \
+ if (current_ipl_level < ipl) \
+ i80321intc_setipl(ipl); \
restore_interrupts(oldirqstate); \
softintr_dispatch(si); \
oldirqstate = disable_interrupts(I32_bit); \
- current_ipl_level = new; \
+ i80321intc_setipl(spl_save); \
}
do {
- DO_SOFTINT(SI_SOFTSERIAL);
- DO_SOFTINT(SI_SOFTNET);
- DO_SOFTINT(SI_SOFTCLOCK);
- DO_SOFTINT(SI_SOFT);
- } while( softint_ipending & i80321_imask[current_ipl_level] );
+ DO_SOFTINT(SI_SOFTSERIAL, IPL_SOFTSERIAL);
+ DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
+ DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
+ DO_SOFTINT(SI_SOFT, IPL_SOFT);
+ } while (softint_pending & i80321intc_smask[current_ipl_level]);
+
processing = 0;
restore_interrupts(oldirqstate);
}
-int spl_debug;
-int nesting;
void
splx(int new)
{
+ i80321intc_setipl(new);
- int oldirqstate, hwpend;
-
- current_ipl_level = new;
-
- hwpend = (i80321_ipending & ICU_INT_HWMASK) & ~i80321_imask[new];
- if (hwpend != 0) {
- oldirqstate = disable_interrupts(I32_bit);
- intr_enabled |= hwpend;
- i80321_set_intrmask();
- restore_interrupts(oldirqstate);
- }
- if (spl_debug) {
- nesting ++;
- if (nesting == 1)
- printf("sX %d\n", new);
- nesting --;
- }
-
- if ((softint_ipending & INT_SWMASK) & ~i80321_imask[new])
- i80321_do_pending();
+ if (softint_pending & i80321intc_smask[current_ipl_level])
+ i80321intc_do_pending();
}
int
-_spllower(int ipl)
+_spllower(int new)
{
-
- extern int i80321_imask[];
int old = current_ipl_level;
-
- splx(i80321_imask[ipl]);
- if (spl_debug) {
- nesting ++;
- if (nesting == 1)
- printf("sL %d\n", ipl);
- nesting --;
- }
- return(old);
+ splx(new);
+ return (old);
}
int
-_splraise(int ipl)
+_splraise(int new)
{
-
- int old;
-
+ int old;
old = current_ipl_level;
- if (ipl > old)
- current_ipl_level = ipl;
- if (spl_debug) {
- nesting ++;
- if (nesting == 1)
- printf("sR %d\n", ipl);
- nesting --;
- }
-
+ if (new > old)
+ i80321intc_setipl(new);
return (old);
}
@@ -456,13 +232,13 @@ _setsoftintr(int si)
{
int oldirqstate;
- oldirqstate = disable_interrupts(I32_bit);
- softint_ipending |= SI_TO_IRQBIT(si);
+ oldirqstate = disable_interrupts(I32_bit);
+ softint_pending |= SI_TO_IRQBIT(si);
restore_interrupts(oldirqstate);
/* Process unmasked pending soft interrupts. */
- if ((softint_ipending & INT_SWMASK) & ~i80321_imask[current_ipl_level])
- i80321_do_pending();
+ if (softint_pending & i80321intc_smask[current_ipl_level])
+ i80321intc_do_pending();
}
/*
@@ -472,45 +248,32 @@ _setsoftintr(int si)
* to make sure the ICU is in a pristine state.
*/
void
-i80321_icu_init(void)
+i80321intc_intr_init(void)
{
- intr_enabled = 0; /* All interrupts disabled */
- i80321_set_intrmask();
+ i80321intc_write_intctl(0);
- intr_steer = 0; /* All interrupts steered to IRQ */
- i80321_set_intrsteer();
+ i80321intc_write_steer(0);
}
-
-struct {
- int id;
- struct evcount ev;
-} i80321_spur[NIRQ];
-
+
/*
* i80321_intr_init:
*
- * Initialize the rest of the interrupt subsystem, making it
- * ready to handle interrupts from devices.
- */
+ * Initialize the rest of the interrupt subsystem, making it
+ * ready to handle interrupts from devices.
+ */
void
-i80321_intr_init(void)
+i80321intc_init(void)
{
struct intrq *iq;
int i;
-
- intr_enabled = 0;
-
+
for (i = 0; i < NIRQ; i++) {
- iq = &intrq[i];
+ iq = &i80321_handler[i];
TAILQ_INIT(&iq->iq_list);
-
- i80321_spur[i].id = i;
- evcount_attach(&i80321_spur[i].ev, "spur",
- (void *)&i80321_spur[i].id, &evcount_intr);
- }
-
- i80321_intr_calculate_masks();
-
+ }
+
+ i80321intc_calc_mask();
+
/* Enable IRQs (don't yet use FIQs). */
enable_interrupts(I32_bit);
}
@@ -521,7 +284,7 @@ i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
{
struct intrq *iq;
struct intrhand *ih;
- u_int oldirqstate;
+ uint32_t oldirqstate;
if (irq < 0 || irq > NIRQ)
panic("i80321_intr_establish: IRQ %d out of range", irq);
@@ -529,14 +292,14 @@ i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
if (ih == NULL)
return (NULL);
-
+
ih->ih_func = func;
ih->ih_arg = arg;
ih->ih_ipl = ipl;
ih->ih_name = name;
ih->ih_irq = irq;
-
- iq = &intrq[irq];
+
+ iq = &i80321_handler[irq];
if (name != NULL)
evcount_attach(&ih->ih_count, name, (void *)&ih->ih_irq,
@@ -546,133 +309,75 @@ i80321_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
iq->iq_ist = IST_LEVEL;
oldirqstate = disable_interrupts(I32_bit);
-
+
TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
-
- i80321_intr_calculate_masks();
+
+ i80321intc_calc_mask();
restore_interrupts(oldirqstate);
-
+
return (ih);
}
+
void
-i80321_intr_disestablish(void *cookie)
+i80321_intr_disestablish(void *cookie)
{
struct intrhand *ih = cookie;
- struct intrq *iq = &intrq[ih->ih_irq];
+ struct intrq *iq = &i80321_handler[ih->ih_irq];
int oldirqstate;
-
+
oldirqstate = disable_interrupts(I32_bit);
TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
if (ih->ih_name != NULL)
evcount_detach(&ih->ih_count);
- i80321_intr_calculate_masks();
+ i80321intc_calc_mask();
restore_interrupts(oldirqstate);
}
-void
-i80321_irq_handler(void *v)
+void
+i80321_irq_handler(void *arg)
{
- struct clockframe *frame = v;
- struct intrq *iq;
+ struct clockframe *frame = arg;
+ uint32_t hwpend;
+ int irq;
+ int saved_spl_level;
struct intrhand *ih;
- int oldirqstate, pipl, irq, ibit, hwpend;
- int spur = 1;
-
- pipl = current_ipl_level;
-
- hwpend = i80321_iintsrc_read();
-
- /*
- * Disable all the interrupts that are pending. We will
- * reenable them once they are processed and not masked.
- */
- intr_enabled &= ~hwpend;
- i80321_set_intrmask();
+
+ saved_spl_level = current_ipl_level;
+ /* get pending IRQs */
+ hwpend = i80321intc_read_intsrc();
- while (hwpend != 0) {
- irq = ffs(hwpend) - 1;
- ibit = (1U << irq);
+ while ((irq = find_first_bit(hwpend)) >= 0) {
+ /* XXX: Should we handle IRQs in priority order? */
+
+ /* raise spl to stop interrupts of lower priorities */
+ if (saved_spl_level < i80321_handler[irq].iq_irq)
+ i80321intc_setipl(i80321_handler[irq].iq_irq);
-#if 0
- if (irq != 9)
- printf("irq %d\n", irq);
+#ifdef notyet
+ /* Enable interrupt */
+ restore_interrupts(I32_bit);
#endif
-
- hwpend &= ~ibit;
-
- if (i80321_imask[pipl] & ibit) {
- /*
- * IRQ is masked; mark it as pending and check
- * the next one. Note: the IRQ is already disabled.
- */
- i80321_ipending |= ibit;
- continue;
- }
-
- i80321_ipending &= ~ibit;
-
- iq = &intrq[irq];
- uvmexp.intrs++;
- current_ipl_level = iq->iq_irq;
- oldirqstate = enable_interrupts(I32_bit);
- for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
- ih = TAILQ_NEXT(ih, ih_list)) {
- if ((*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame)) {
+ TAILQ_FOREACH(ih, &i80321_handler[irq].iq_list, ih_list) {
+ if ((ih->ih_func)( ih->ih_arg == 0
+ ? frame : ih->ih_arg))
ih->ih_count.ec_count++;
- spur = 0;
- }
}
- restore_interrupts(oldirqstate);
-
- if (spur == 1)
- i80321_spur[irq].ev.ec_count++;
-
- current_ipl_level = pipl;
-
- /* Re-enable this interrupt now that's it's cleared. */
- intr_enabled |= ibit;
- i80321_set_intrmask();
-
- /*
- * Don't forget to include interrupts which may have
- * arrived in the meantime.
- */
- hwpend |= ((i80321_ipending & ICU_INT_HWMASK) & ~i80321_imask[pipl]);
+#ifdef notyet
+ /* Disable interrupt */
+ disable_interrupts(I32_bit);
+#endif
+ hwpend &= ~(1<<irq);
}
- /* Check for pendings soft intrs. */
- if ((softint_ipending & INT_SWMASK) & ~i80321_imask[current_ipl_level]) {
- oldirqstate = enable_interrupts(I32_bit);
- i80321_do_pending();
- restore_interrupts(oldirqstate);
- }
-}
-uint32_t get_pending_irq(void);
-uint32_t
-get_pending_irq()
-{
- uint32_t pending;
-#if 1
- uint32_t ointr_enabled;
- uint32_t oldirqstate;
- oldirqstate = disable_interrupts(I32_bit);
- ointr_enabled = intr_enabled;
- intr_enabled = 0xffffffff;
- __asm volatile("mcr p6, 0, %0, c0, c0, 0":: "r" (0xffffffff));
- i80321_set_intrmask();
-#endif
- __asm volatile("mrc p6, 0, %0, c8, c0, 0"
- : "=r" (pending));
-#if 1
- intr_enabled = ointr_enabled;
- i80321_set_intrmask();
- restore_interrupts(oldirqstate);
-#endif
- return pending;
+ /* restore spl to that was when this interrupt happen */
+ i80321intc_setipl(saved_spl_level);
+
+ if(softint_pending & i80321intc_smask[current_ipl_level])
+ i80321intc_do_pending();
}