Module Name: src
Committed By: cliff
Date: Sun Mar 21 21:25:30 UTC 2010
Modified Files:
src/sys/arch/mips/rmi [matt-nb5-mips64]: rmixl_intr.c
Log Message:
- rework to make full use of RMI extended interrupt management
provided by EIRR/EIMR registers
- depends on rmixl_spl.S
- add support for IRT based interrupt routing; for now we are still routing
all IRT interrupts to CPU#0.
- note that count/compare clock, IPI and FMN are handled by each CPU since
these are local interrupt sources.
- further changes are still needed for XLR and XLP support
To generate a diff of this commit:
cvs rdiff -u -r1.1.2.14 -r1.1.2.15 src/sys/arch/mips/rmi/rmixl_intr.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/mips/rmi/rmixl_intr.c
diff -u src/sys/arch/mips/rmi/rmixl_intr.c:1.1.2.14 src/sys/arch/mips/rmi/rmixl_intr.c:1.1.2.15
--- src/sys/arch/mips/rmi/rmixl_intr.c:1.1.2.14 Sun Feb 28 03:28:01 2010
+++ src/sys/arch/mips/rmi/rmixl_intr.c Sun Mar 21 21:25:30 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: rmixl_intr.c,v 1.1.2.14 2010/02/28 03:28:01 matt Exp $ */
+/* $NetBSD: rmixl_intr.c,v 1.1.2.15 2010/03/21 21:25:30 cliff Exp $ */
/*-
* Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
@@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rmixl_intr.c,v 1.1.2.14 2010/02/28 03:28:01 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rmixl_intr.c,v 1.1.2.15 2010/03/21 21:25:30 cliff Exp $");
#include "opt_ddb.h"
#define __INTR_PRIVATE
@@ -75,6 +75,8 @@
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
+#include <sys/atomic.h>
+#include <sys/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -85,9 +87,13 @@
#include <mips/rmi/rmixlreg.h>
#include <mips/rmi/rmixlvar.h>
+#include <mips/rmi/rmixl_cpuvar.h>
+#include <mips/rmi/rmixl_intr.h>
+
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+// #define IOINTR_DEBUG 1
#ifdef IOINTR_DEBUG
int iointr_debug = IOINTR_DEBUG;
# define DPRINTF(x) do { if (iointr_debug) printf x ; } while(0)
@@ -99,39 +105,25 @@
RMIXL_IOREG_READ(RMIXL_IO_DEV_PIC + (off))
#define RMIXL_PICREG_WRITE(off, val) \
RMIXL_IOREG_WRITE(RMIXL_IO_DEV_PIC + (off), (val))
+
/*
- * This is a mask of bits to clear in the SR when we go to a
- * given hardware interrupt priority level.
- * _SR_BITS_DFLT bits are to be always clear (disabled)
- */
-#define _SR_BITS_DFLT (MIPS_INT_MASK_2|MIPS_INT_MASK_3|MIPS_INT_MASK_4)
-static const struct ipl_sr_map rmixl_ipl_sr_map = {
- .sr_bits = {
- [IPL_NONE] = _SR_BITS_DFLT,
- [IPL_SOFTCLOCK] = _SR_BITS_DFLT | MIPS_SOFT_INT_MASK_0,
- [IPL_SOFTNET] = _SR_BITS_DFLT | MIPS_SOFT_INT_MASK,
- [IPL_VM] = _SR_BITS_DFLT | MIPS_SOFT_INT_MASK | MIPS_INT_MASK_0,
- [IPL_SCHED] = MIPS_INT_MASK,
- [IPL_HIGH] = MIPS_INT_MASK,
- },
-};
+ * do not clear these when acking EIRR
+ * (otherwise they get lost)
+ */
+#define RMIXL_EIRR_PRESERVE_MASK \
+ ((MIPS_INT_MASK_5|MIPS_SOFT_INT_MASK) >> 8)
/*
- * 'IRQs' here are indiividual interrupt sources
- * each has a slot in the Interrupt Redirection Table (IRT)
- * in the order listed
- *
- * NOTE: many irq sources depend on the chip family
- * XLS1xx vs. XLS2xx vs. XLS3xx vs. XLS6xx
- * use the right table for the CPU that's running.
+ * IRT assignments depends on the RMI chip family
+ * (XLS1xx vs. XLS2xx vs. XLS3xx vs. XLS6xx)
+ * use the right irq (and display string table) for the CPU that's running.
*/
/*
- * rmixl_irqnames_xls1xx
+ * rmixl_irtnames_xls1xx
* - use for XLS1xx, XLS2xx, XLS4xx-Lite
*/
-#define NIRQS 32
-static const char * const rmixl_irqnames_xls1xx[NIRQS] = {
+static const char * const rmixl_irtnames_xls1xx[NIRTS] = {
"int 0 (watchdog)", /* 0 */
"int 1 (timer0)", /* 1 */
"int 2 (timer1)", /* 2 */
@@ -167,10 +159,10 @@
};
/*
- * rmixl_irqnames_xls4xx:
+ * rmixl_irtnames_xls4xx:
* - use for XLS4xx, XLS6xx
*/
-static const char * const rmixl_irqnames_xls4xx[NIRQS] = {
+static const char * const rmixl_irtnames_xls4xx[NIRTS] = {
"int 0 (watchdog)", /* 0 */
"int 1 (timer0)", /* 1 */
"int 2 (timer1)", /* 2 */
@@ -206,10 +198,11 @@
};
/*
- * rmixl_irqnames_generic:
+ * rmixl_vecnames_common:
* - use for unknown cpu implementation
+ * - covers all vectors, not just IRT intrs
*/
-static const char * const rmixl_irqnames_generic[NIRQS] = {
+static const char * const rmixl_vecnames_common[NINTRVECS] = {
"int 0", /* 0 */
"int 1", /* 1 */
"int 2", /* 2 */
@@ -242,77 +235,92 @@
"int 29", /* 29 */
"int 30", /* 30 */
"int 31", /* 31 */
+ "int 32 (ipi)", /* 32 */
+ "int 33 (fmn)", /* 33 */
+ "int 34", /* 34 */
+ "int 35", /* 35 */
+ "int 36", /* 36 */
+ "int 37", /* 37 */
+ "int 38", /* 38 */
+ "int 39", /* 39 */
+ "int 40", /* 40 */
+ "int 41", /* 41 */
+ "int 42", /* 42 */
+ "int 43", /* 43 */
+ "int 44", /* 44 */
+ "int 45", /* 45 */
+ "int 46", /* 46 */
+ "int 47", /* 47 */
+ "int 48", /* 48 */
+ "int 49", /* 49 */
+ "int 50", /* 50 */
+ "int 51", /* 51 */
+ "int 52", /* 52 */
+ "int 53", /* 53 */
+ "int 54", /* 54 */
+ "int 55", /* 55 */
+ "int 56", /* 56 */
+ "int 57", /* 57 */
+ "int 58", /* 58 */
+ "int 59", /* 59 */
+ "int 60", /* 60 */
+ "int 61", /* 61 */
+ "int 62", /* 63 */
+ "int 63", /* 63 */
};
/*
- * per-IRQ event stats
+ * mask of CPUs attached
+ * once they are attached, this var is read-only so mp safe
*/
-struct rmixl_irqtab {
- struct evcnt irq_count;
- void *irq_ih;
-};
-static struct rmixl_irqtab rmixl_irqtab[NIRQS];
+static uint32_t cpu_present_mask;
+rmixl_intrhand_t rmixl_intrhand[NINTRVECS];
-/*
- * 'vectors' here correspond to IRT Entry vector numbers
- * - IRT Entry vector# is bit# in EIRR
- * - note that EIRR[7:0] == CAUSE[15:8]
- * - we actually only use the first _IPL_N bits
- * (less than 8)
- *
- * each IRT entry gets routed to a vector
- * (if and when that interrupt is established)
- * the vectors are shared on a per-IPL basis
- * which simplifies dispatch
- *
- * XXX use of mips64 extended IRQs is TBD
- */
-#define NINTRVECS _IPL_N
+#ifdef DIAGNOSTIC
+static int rmixl_pic_init_done;
+#endif
-/*
- * translate IPL to vector number
- */
-static const int rmixl_iplvec[_IPL_N] = {
- [IPL_NONE] = -1, /* XXX */
- [IPL_SOFTCLOCK] = 0,
- [IPL_SOFTNET] = 1,
- [IPL_VM] = 2,
- [IPL_SCHED] = 3,
-};
-/*
- * list and ref count manage sharing of each vector
- */
-struct rmixl_intrvec {
- LIST_HEAD(, evbmips_intrhand) iv_list;
- uint32_t iv_ack;
- rmixl_intr_trigger_t iv_trigger;
- rmixl_intr_polarity_t iv_polarity;
- u_int iv_refcnt;
-};
-static struct rmixl_intrvec rmixl_intrvec[NINTRVECS];
+static void rmixl_irt_init(int);
+static void rmixl_irt_disestablish(int);
+static void rmixl_irt_establish(int, int,
+ rmixl_intr_trigger_t, rmixl_intr_polarity_t);
-#ifdef DIAGNOSTIC
-static int evbmips_intr_init_done;
+#ifdef MULTIPROCESSOR
+static int rmixl_send_ipi(struct cpu_info *, int);
+static int rmixl_ipi_intr(void *);
+#endif
+
+#if defined(IOINTR_DEBUG) || defined(DIAGNOSTIC)
+int rmixl_intrhand_print_subr(int);
+int rmixl_intrhand_print(void);
+int rmixl_irt_print(void);
#endif
-static void rmixl_intr_irt_init(int);
-static void rmixl_intr_irt_disestablish(int);
-static void rmixl_intr_irt_establish(int, int, rmixl_intr_trigger_t,
- rmixl_intr_polarity_t, int);
+static inline u_int
+dclz(uint64_t val)
+{
+ int nlz;
+ asm volatile("dclz %0, %1;"
+ : "=r"(nlz) : "r"(val));
+
+ return nlz;
+}
static inline void
-pic_irt_print(const char *s, const int n, u_int irq)
+rmixl_irt_entry_print(u_int irq)
{
-#ifdef IOINTR_DEBUG
+#if defined(IOINTR_DEBUG) || defined(DDB)
uint32_t c0, c1;
+ if ((irq < 0) || (irq > NIRTS))
+ return;
c0 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC0(irq));
c1 = RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC1(irq));
- printf("%s:%d: irq %d: c0 %#x, c1 %#x\n", s, n, irq, c0, c1);
+ printf("irt[%d]: %#x, %#x\n", irq, c0, c1);
#endif
}
@@ -320,28 +328,35 @@
evbmips_intr_init(void)
{
uint32_t r;
- int i;
KASSERT(cpu_rmixls(mips_options.mips_cpu));
- ipl_sr_map = rmixl_ipl_sr_map;
-#ifdef DIAGNOSTIC
- if (evbmips_intr_init_done != 0)
- panic("%s: evbmips_intr_init_done %d",
- __func__, evbmips_intr_init_done);
+#ifdef IOINTR_DEBUG
+ printf("IPL_NONE=%d, mask %#"PRIx64"\n",
+ IPL_NONE, ipl_eimr_map[IPL_NONE]);
+ printf("IPL_SOFTCLOCK=%d, mask %#"PRIx64"\n",
+ IPL_SOFTCLOCK, ipl_eimr_map[IPL_SOFTCLOCK]);
+ printf("IPL_SOFTNET=%d, mask %#"PRIx64"\n",
+ IPL_SOFTNET, ipl_eimr_map[IPL_SOFTNET]);
+ printf("IPL_VM=%d, mask %#"PRIx64"\n",
+ IPL_VM, ipl_eimr_map[IPL_VM]);
+ printf("IPL_SCHED=%d, mask %#"PRIx64"\n",
+ IPL_SCHED, ipl_eimr_map[IPL_HIGH]);
+ printf("IPL_HIGH=%d, mask %#"PRIx64"\n",
+ IPL_HIGH, ipl_eimr_map[IPL_NONE]);
#endif
- for (i=0; i < NIRQS; i++) {
- evcnt_attach_dynamic(&rmixl_irqtab[i].irq_count,
- EVCNT_TYPE_INTR, NULL, "rmixl", rmixl_intr_string(i));
- rmixl_irqtab[i].irq_ih = NULL;
- }
+#ifdef DIAGNOSTIC
+ if (rmixl_pic_init_done != 0)
+ panic("%s: rmixl_pic_init_done %d",
+ __func__, rmixl_pic_init_done);
+#endif
- for (i=0; i < NINTRVECS; i++) {
- LIST_INIT(&rmixl_intrvec[i].iv_list);
- rmixl_intrvec[i].iv_ack = 0;
- rmixl_intrvec[i].iv_refcnt = 0;
- }
+ /*
+ * initialize (zero) all IRT Entries in the PIC
+ */
+ for (int i=0; i < NIRTS; i++)
+ rmixl_irt_init(i);
/*
* disable watchdog NMI, timers
@@ -354,31 +369,85 @@
r &= RMIXL_PIC_CONTROL_RESV|RMIXL_PIC_CONTROL_WATCHDOG_ENB;
RMIXL_PICREG_WRITE(RMIXL_PIC_CONTROL, r);
- /*
- * initialize all IRT Entries
- */
- for (i=0; i < NIRQS; i++)
- rmixl_intr_irt_init(i);
-
- /*
- * establish IRT entry for mips3 clock interrupt
- */
- rmixl_intr_irt_establish(7, IPL_CLOCK, RMIXL_INTR_LEVEL,
- RMIXL_INTR_HIGH, rmixl_iplvec[IPL_CLOCK]);
-
#ifdef DIAGNOSTIC
- evbmips_intr_init_done = 1;
+ rmixl_pic_init_done = 1;
#endif
+
}
+/*
+ * establish vector for mips3 count/compare clock interrupt
+ * this ensures we enable in EIRR,
+ * even though cpu_intr() handles the interrupt
+ */
+void *
+rmixl_intr_init_clk(void)
+{
+ int vec = ffs(MIPS_INT_MASK_5 >> 8) - 1;
+ void *ih = rmixl_vec_establish(vec, 0, IPL_SCHED, NULL, NULL);
+ if (ih == NULL)
+ panic("%s: establish vec %d failed", __func__, vec);
+
+ return ih;
+}
+
+#ifdef MULTIPROCESSOR
+/*
+ * establish IPI interrupt and send function
+ */
+void *
+rmixl_intr_init_ipi(void)
+{
+ void *ih = rmixl_vec_establish(RMIXL_INTRVEC_IPI, -1, IPL_SCHED,
+ rmixl_ipi_intr, NULL);
+ if (ih == NULL)
+ panic("%s: establish vec %d failed",
+ __func__, RMIXL_INTRVEC_IPI);
+
+ mips_locoresw.lsw_send_ipi = rmixl_send_ipi;
+
+ return ih;
+}
+#endif /* MULTIPROCESSOR */
+
+/*
+ * initialize per-cpu interrupt stuff in softc
+ * accumulate per-cpu bits in 'cpu_present_mask'
+ */
+void
+rmixl_intr_init_cpu(struct cpu_info *ci)
+{
+ struct rmixl_cpu_softc *sc = (void *)ci->ci_softc;
+ KASSERT(sc != NULL);
+
+ /* zero the EIRR ? */
+ uint64_t eirr = 0;
+ asm volatile("dmtc0 %0, $9, 6;" :: "r"(eirr));
+
+ for (int vec=0; vec < NINTRVECS; vec++)
+ evcnt_attach_dynamic(&sc->sc_vec_evcnts[vec],
+ EVCNT_TYPE_INTR, NULL,
+ device_xname(sc->sc_dev),
+ rmixl_intr_string(vec));
+
+ KASSERT(ci->ci_cpuid < (sizeof(cpu_present_mask) * 8));
+ cpu_present_mask |= 1 << ci->ci_cpuid;
+}
+
+/*
+ * rmixl_intr_string - return pointer to display name of a PIC-based interrupt
+ */
const char *
rmixl_intr_string(int irq)
{
const char *name;
- if (irq < 0 || irq >= NIRQS)
- panic("%s: irq %d out of range, max %d",
- __func__, irq, NIRQS - 1);
+ if (irq < 0 || irq >= NINTRVECS)
+ panic("%s: irq index %d out of range, max %d",
+ __func__, irq, NIRTS - 1);
+
+ if (irq >= NIRTS)
+ return rmixl_vecnames_common[irq];
switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
case MIPS_XLS104:
@@ -387,17 +456,17 @@
case MIPS_XLS208:
case MIPS_XLS404LITE:
case MIPS_XLS408LITE:
- name = rmixl_irqnames_xls1xx[irq];
+ name = rmixl_irtnames_xls1xx[irq];
break;
case MIPS_XLS404:
case MIPS_XLS408:
case MIPS_XLS416:
case MIPS_XLS608:
case MIPS_XLS616:
- name = rmixl_irqnames_xls4xx[irq];
+ name = rmixl_irtnames_xls4xx[irq];
break;
default:
- name = rmixl_irqnames_generic[irq];
+ name = rmixl_vecnames_common[irq];
break;
}
@@ -405,309 +474,384 @@
}
/*
- * rmixl_intr_irt_init
- * - invalidate IRT Entry for irq
- * - unmask Thread#0 in low word (assume we only have 1 thread)
+ * rmixl_irt_thread_mask
+ *
+ * given a bitmask of cpus, return a, IRT thread mask
*/
-static void
-rmixl_intr_irt_init(int irq)
+static uint32_t
+rmixl_irt_thread_mask(int cpumask)
{
- uint32_t threads;
+ uint32_t irtc0;
+
+#if defined(MULTIPROCESSOR)
+#ifndef NOTYET
+ if (cpumask == -1)
+ return 1; /* XXX TMP FIXME */
+#endif
-#if defined(MULTIPROCESSOR) && defined(NOTYET)
/*
- * XXX make sure the threads are ours?
+ * discount cpus not present
*/
+ cpumask &= cpu_present_mask;
+
switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
case MIPS_XLS104:
case MIPS_XLS204:
case MIPS_XLS404:
case MIPS_XLS404LITE:
- threads = __BITS(5,4) | __BITS(1,0);
+ irtc0 = ((cpumask >> 2) << 4) | (cpumask & __BITS(1,0));
+ irtc0 &= (__BITS(5,4) | __BITS(1,0));
break;
case MIPS_XLS108:
case MIPS_XLS208:
case MIPS_XLS408:
case MIPS_XLS408LITE:
case MIPS_XLS608:
- threads = __BITS(7,0);
+ irtc0 = cpumask & __BITS(7,0);
break;
case MIPS_XLS416:
case MIPS_XLS616:
- threads = __BITS(15,0);
+ irtc0 = cpumask & __BITS(15,0);
break;
default:
panic("%s: unknown cpu ID %#x\n", __func__,
mips_options.mips_cpu_id);
}
#else
- threads = 1;
-#endif
+ irtc0 = 1;
+#endif /* MULTIPROCESSOR */
+
+ return irtc0;
+}
+
+/*
+ * rmixl_irt_init
+ * - invalidate IRT Entry for irq
+ * - unmask Thread#0 in low word (assume we only have 1 thread)
+ */
+static void
+rmixl_irt_init(int irq)
+{
RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */
- RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), threads); /* low word */
+ RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), 0); /* low word */
}
/*
- * rmixl_intr_irt_disestablish
+ * rmixl_irt_disestablish
* - invalidate IRT Entry for irq
* - writes to IRTENTRYC1 only; leave IRTENTRYC0 as-is
*/
static void
-rmixl_intr_irt_disestablish(int irq)
+rmixl_irt_disestablish(int irq)
{
DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, 0));
- RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), 0); /* high word */
+ rmixl_irt_init(irq);
}
/*
- * rmixl_intr_irt_establish
- * - construct and IRT Entry for irq and write to PIC
- * - writes to IRTENTRYC1 only; assumes IRTENTRYC0 has been initialized
+ * rmixl_irt_establish
+ * - construct an IRT Entry for irq and write to PIC
*/
static void
-rmixl_intr_irt_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
- rmixl_intr_polarity_t polarity, int vec)
+rmixl_irt_establish(int irq, int cpumask, rmixl_intr_trigger_t trigger,
+ rmixl_intr_polarity_t polarity)
{
uint32_t irtc1;
+ uint32_t irtc0;
+
+ switch (trigger) {
+ case RMIXL_TRIG_EDGE:
+ case RMIXL_TRIG_LEVEL:
+ break;
+ default:
+ panic("%s: bad trigger %d\n", __func__, trigger);
+ }
+
+ switch (polarity) {
+ case RMIXL_POLR_RISING:
+ case RMIXL_POLR_HIGH:
+ case RMIXL_POLR_FALLING:
+ case RMIXL_POLR_LOW:
+ break;
+ default:
+ panic("%s: bad polarity %d\n", __func__, polarity);
+ }
+
+ /*
+ * XXX IRT entries are not shared
+ */
+ KASSERT(RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC0(irq)) == 0);
+ KASSERT(RMIXL_PICREG_READ(RMIXL_PIC_IRTENTRYC1(irq)) == 0);
+
+ irtc0 = rmixl_irt_thread_mask(cpumask);
irtc1 = RMIXL_PIC_IRTENTRYC1_VALID;
irtc1 |= RMIXL_PIC_IRTENTRYC1_GL; /* local */
- if (trigger == RMIXL_INTR_LEVEL)
+ if (trigger == RMIXL_TRIG_LEVEL)
irtc1 |= RMIXL_PIC_IRTENTRYC1_TRG;
- if ((polarity == RMIXL_INTR_FALLING) || (polarity == RMIXL_INTR_LOW))
+ if ((polarity == RMIXL_POLR_FALLING) || (polarity == RMIXL_POLR_LOW))
irtc1 |= RMIXL_PIC_IRTENTRYC1_P;
- irtc1 |= vec;
+ irtc1 |= irq; /* route to vector 'irq' */
/*
- * write IRT Entry to PIC (high word only)
+ * write IRT Entry to PIC
*/
- DPRINTF(("%s: irq %d, irtc1 %#x\n", __func__, irq, irtc1));
- RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), irtc1);
+ DPRINTF(("%s: irq %d, irtc0 %#x, irtc1 %#x\n",
+ __func__, irq, irtc0, irtc1));
+ RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC0(irq), irtc0); /* low word */
+ RMIXL_PICREG_WRITE(RMIXL_PIC_IRTENTRYC1(irq), irtc1); /* high word */
}
void *
-rmixl_intr_establish(int irq, int ipl, rmixl_intr_trigger_t trigger,
- rmixl_intr_polarity_t polarity, int (*func)(void *), void *arg)
+rmixl_vec_establish(int vec, int cpumask, int ipl,
+ int (*func)(void *), void *arg)
{
- struct evbmips_intrhand *ih;
- struct rmixl_intrvec *ivp;
- int vec;
+ rmixl_intrhand_t *ih;
int s;
+ DPRINTF(("%s: vec %d, cpumask %#x, ipl %d, func %p, arg %p, "
+ "vec %d\n",
+ __func__, vec, cpumask, ipl, func, arg, vec));
#ifdef DIAGNOSTIC
- if (evbmips_intr_init_done == 0)
+ if (rmixl_pic_init_done == 0)
panic("%s: called before evbmips_intr_init", __func__);
#endif
/*
- * check args and assemble an IRT Entry
+ * check args
*/
- if (irq < 0 || irq >= NIRQS)
- panic("%s: irq %d out of range, max %d",
- __func__, irq, NIRQS - 1);
+ if (vec < 0 || vec >= NINTRVECS)
+ panic("%s: vec %d out of range, max %d",
+ __func__, vec, NINTRVECS - 1);
if (ipl <= 0 || ipl >= _IPL_N)
panic("%s: ipl %d out of range, min %d, max %d",
__func__, ipl, 1, _IPL_N - 1);
- if (rmixl_irqtab[irq].irq_ih != NULL)
- panic("%s: irq %d busy", __func__, irq);
- switch (trigger) {
- case RMIXL_INTR_EDGE:
- case RMIXL_INTR_LEVEL:
- break;
- default:
- panic("%s: bad trigger %d\n", __func__, trigger);
- }
+ s = splhigh();
- switch (polarity) {
- case RMIXL_INTR_RISING:
- case RMIXL_INTR_HIGH:
- case RMIXL_INTR_FALLING:
- case RMIXL_INTR_LOW:
- break;
- default:
- panic("%s: bad polarity %d\n", __func__, polarity);
- }
+ ih = &rmixl_intrhand[vec];
- /*
- * ipl determines which vector to use
- */
- vec = rmixl_iplvec[ipl];
- DPRINTF(("%s: irq %d, ipl %d, vec %d\n", __func__, irq, ipl, vec));
- KASSERT((vec & ~RMIXL_PIC_IRTENTRYC1_INTVEC) == 0);
+ ih->ih_func = func;
+ ih->ih_arg = arg;
+ ih->ih_irq = vec;
+ ih->ih_ipl = ipl;
+ ih->ih_cpumask = cpumask;
- s = splhigh();
+ splx(s);
+
+ return ih;
+}
+
+void *
+rmixl_intr_establish(int irq, int cpumask, int ipl, rmixl_intr_trigger_t trigger,
+ rmixl_intr_polarity_t polarity, int (*func)(void *), void *arg)
+{
+ rmixl_intrhand_t *ih;
+ int s;
- ivp = &rmixl_intrvec[vec];
- if (ivp->iv_refcnt == 0) {
- ivp->iv_trigger = trigger;
- ivp->iv_polarity = polarity;
- } else {
- if (ivp->iv_trigger != trigger) {
-#ifdef DIAGNOSTIC
- printf("%s: vec %d, irqs {", __func__, vec);
- LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
- printf(" %d", ih->ih_irq);
- }
- printf(" } trigger type %d; irq %d wants type %d\n",
- ivp->iv_trigger, irq, trigger);
-#endif
- panic("%s: trigger mismatch at vec %d\n",
- __func__, vec);
- }
- if (ivp->iv_polarity != polarity) {
#ifdef DIAGNOSTIC
- printf("%s: vec %d, irqs {", __func__, vec);
- LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
- printf(" %d", ih->ih_irq);
- }
- printf(" } polarity type %d; irq %d wants type %d\n",
- ivp->iv_polarity, irq, polarity);
-#endif
- panic("%s: polarity mismatch at vec %d\n",
- __func__, vec);
- }
- }
- ivp->iv_ack |= (1 << irq);
+ if (rmixl_pic_init_done == 0)
+ panic("%s: called before rmixl_pic_init_done", __func__);
+#endif
/*
- * allocate and initialize an interrupt handle
+ * check args
*/
- ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
- if (ih == NULL)
- goto out;
+ if (irq < 0 || irq >= NINTRVECS)
+ panic("%s: irq %d out of range, max %d",
+ __func__, irq, NIRTS - 1);
+ if (ipl <= 0 || ipl >= _IPL_N)
+ panic("%s: ipl %d out of range, min %d, max %d",
+ __func__, ipl, 1, _IPL_N - 1);
- ih->ih_func = func;
- ih->ih_arg = arg;
- ih->ih_irq = irq;
- ih->ih_ipl = ipl;
+ DPRINTF(("%s: irq %d, ipl %d\n", __func__, irq, ipl));
- /*
- * mark this irq as established, busy
- */
- rmixl_irqtab[irq].irq_ih = ih;
+ s = splhigh();
/*
- * link this ih into the tables and bump reference count
+ * establish vector
*/
- LIST_INSERT_HEAD(&ivp->iv_list, ih, ih_q);
- ivp->iv_refcnt++;
+ ih = rmixl_vec_establish(irq, cpumask, ipl, func, arg);
/*
* establish IRT Entry
*/
- rmixl_intr_irt_establish(irq, ipl, trigger, polarity, vec);
+ if (irq < 32)
+ rmixl_irt_establish(irq, cpumask, trigger, polarity);
- out:
splx(s);
return ih;
}
void
+rmixl_vec_disestablish(void *cookie)
+{
+ rmixl_intrhand_t *ih = cookie;
+ int s;
+
+ KASSERT(ih = &rmixl_intrhand[ih->ih_irq]);
+
+ s = splhigh();
+
+ ih->ih_func = NULL; /* XXX race */
+
+ splx(s);
+}
+
+void
rmixl_intr_disestablish(void *cookie)
{
- struct evbmips_intrhand *ih = cookie;
- struct rmixl_intrvec *ivp;
- int irq;
+ rmixl_intrhand_t *ih = cookie;
int vec;
int s;
- irq = ih->ih_irq;
- vec = rmixl_iplvec[ih->ih_ipl];
- ivp = &rmixl_intrvec[vec];
+ vec = ih->ih_irq;
+
+ KASSERT(ih = &rmixl_intrhand[vec]);
s = splhigh();
/*
- * disable the IRT Entry (high word only)
+ * disable/invalidate the IRT Entry if needed
*/
- rmixl_intr_irt_disestablish(irq);
+ if (vec < 32)
+ rmixl_irt_disestablish(vec);
/*
- * remove from the table and adjust the reference count
+ * disasociate from vector and free the handle
*/
- LIST_REMOVE(ih, ih_q);
- ivp->iv_refcnt--;
- ivp->iv_ack &= ~(1 << irq);
-
- /*
- * this irq now disestablished, not busy
- */
- rmixl_irqtab[irq].irq_ih = NULL;
+ rmixl_vec_disestablish(cookie);
splx(s);
-
- free(ih, M_DEVBUF);
}
void
-evbmips_iointr(int ipl, vaddr_t pc, uint32_t ipending)
+evbmips_iointr(int ipl, vaddr_t pc, uint32_t pending)
{
- struct evbmips_intrhand *ih;
- struct rmixl_intrvec *ivp;
- int vec;
- uint64_t eirr;
-#ifdef IOINTR_DEBUG
- uint64_t eimr;
+ struct rmixl_cpu_softc *sc = (void *)curcpu()->ci_softc;
- printf("%s: ipl %d, pc %#x, ipending %#x\n",
- __func__, ipl, pc, ipending);
+ DPRINTF(("%s: cpu%ld: ipl %d, pc %#"PRIxVADDR", pending %#x\n",
+ __func__, cpu_number(), ipl, pc, pending));
- asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
- asm volatile("dmfc0 %0, $9, 7;" : "=r"(eimr));
- printf("%s:%d: eirr %#lx, eimr %#lx\n", __func__, __LINE__, eirr, eimr);
-#endif
+ /*
+ * 'pending' arg is a summary that there is something to do
+ * the real pending status is obtained from EIRR
+ */
+ KASSERT(pending == MIPS_INT_MASK_1);
- for (vec = NINTRVECS - 1; vec >= 2; vec--) {
- if ((ipending & (MIPS_SOFT_INT_MASK_0 << vec)) == 0)
- continue;
+ for (;;) {
+ rmixl_intrhand_t *ih;
+ uint64_t eirr;
+ uint64_t vecbit;
+ int vec;
- ivp = &rmixl_intrvec[vec];
+ asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
+#ifdef IOINTR_DEBUG
+ uint64_t eimr;
+ asm volatile("dmfc0 %0, $9, 7;" : "=r"(eimr));
+ printf("%s: eirr %#"PRIx64", eimr %#"PRIx64", mask %#"PRIx64"\n",
+ __func__, eirr, eimr, ipl_eimr_map[ipl-1]);
+#endif /* IOINTR_DEBUG */
+
+ eirr &= ipl_eimr_map[ipl-1];
+ eirr &= ~(MIPS_SOFT_INT_MASK >> 8); /* mask off soft ints */
+ if (eirr == 0)
+ break;
+
+ vec = 63 - dclz(eirr);
+ ih = &rmixl_intrhand[vec];
+
+ int s = splhigh();
+ vecbit = 1ULL << vec;
+ KASSERT ((vecbit & RMIXL_EIRR_PRESERVE_MASK) == 0);
asm volatile("dmfc0 %0, $9, 6;" : "=r"(eirr));
- eirr &= 3;
- eirr |= 1ULL << vec;
+ eirr &= RMIXL_EIRR_PRESERVE_MASK;
+ eirr |= vecbit;
asm volatile("dmtc0 %0, $9, 6;" :: "r"(eirr));
+ splx(s);
-#ifdef IOINTR_DEBUG
- printf("%s: interrupt at vec %d\n",
- __func__, vec);
- if (LIST_EMPTY(&ivp->iv_list))
- printf("%s: unexpected interrupt at vec %d\n",
- __func__, vec);
-#endif
- LIST_FOREACH(ih, &ivp->iv_list, ih_q) {
- pic_irt_print(__func__, __LINE__, ih->ih_irq);
+ if (vec < 32)
RMIXL_PICREG_WRITE(RMIXL_PIC_INTRACK,
- (1 << ih->ih_irq));
- if ((*ih->ih_func)(ih->ih_arg) != 0) {
- rmixl_irqtab[ih->ih_irq].irq_count.ev_count++;
- }
- }
+ (uint32_t)vecbit);
+
+ if (ih->ih_func != NULL)
+ (void)(*ih->ih_func)(ih->ih_arg);
+
+ sc->sc_vec_evcnts[vec].ev_count++;
}
}
-#ifdef DEBUG
-int rmixl_intrvec_print(void);
-int
-rmixl_intrvec_print(void)
+#ifdef MULTIPROCESSOR
+static int
+rmixl_send_ipi(struct cpu_info *ci, int tag)
{
- struct evbmips_intrhand *ih;
- struct rmixl_intrvec *ivp;
- int vec;
+ const cpuid_t cpu = ci->ci_cpuid;
+ uint32_t core = (uint32_t)(cpu >> 2);
+ uint32_t thread = (uint32_t)(cpu & __BITS(1,0));
+ uint64_t req = 1 << tag;
+ uint32_t r;
+ extern volatile u_long cpus_running;
- ivp = &rmixl_intrvec[0];
- for (vec=0; vec < NINTRVECS ; vec++) {
- printf("vec %d, irqs {", vec);
- LIST_FOREACH(ih, &ivp->iv_list, ih_q)
- printf(" %d", ih->ih_irq);
- printf(" } trigger type %d\n", ivp->iv_trigger);
- ivp++;
- }
+ if ((cpus_running & 1 << ci->ci_cpuid) == 0)
+ return -1;
+
+ KASSERT(tag < NIPIS);
+
+ r = (thread << RMIXL_PIC_IPIBASE_ID_THREAD_SHIFT)
+ | (core << RMIXL_PIC_IPIBASE_ID_CORE_SHIFT)
+ | RMIXL_INTRVEC_IPI;
+
+ atomic_or_64(&ci->ci_request_ipis, req);
+
+ RMIXL_PICREG_WRITE(RMIXL_PIC_IPIBASE, r);
+
+ return 0;
+}
+
+static int
+rmixl_ipi_intr(void *arg)
+{
+ struct cpu_info * const ci = curcpu();
+ uint64_t ipi_mask;
+
+ ipi_mask = atomic_swap_64(&ci->ci_request_ipis, 0);
+ if (ipi_mask == 0)
+ return 0;
+
+ ipi_process(ci, ipi_mask);
+
+ return 1;
+}
+#endif /* MULTIPROCESSOR */
+
+#if defined(DIAGNOSTIC) || defined(IOINTR_DEBUG)
+int
+rmixl_intrhand_print_subr(int vec)
+{
+ rmixl_intrhand_t *ih = &rmixl_intrhand[vec];
+ printf("vec %d: func %p, arg %p, irq %d, ipl %d, mask %#x\n",
+ vec, ih->ih_func, ih->ih_arg, ih->ih_irq, ih->ih_ipl,
+ ih->ih_cpumask);
+ return 0;
+}
+int
+rmixl_intrhand_print(void)
+{
+ for (int vec=0; vec < NINTRVECS ; vec++)
+ rmixl_intrhand_print_subr(vec);
+ return 0;
+}
+int
+rmixl_irt_print(void)
+{
+ printf("%s:\n", __func__);
+ for (int irt=0; irt < NIRTS ; irt++)
+ rmixl_irt_entry_print(irt);
return 0;
}
#endif