aboutsummaryrefslogtreecommitdiff
path: root/sys/mips/sibyte/sb_zbbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/mips/sibyte/sb_zbbus.c')
-rw-r--r--sys/mips/sibyte/sb_zbbus.c78
1 files changed, 72 insertions, 6 deletions
diff --git a/sys/mips/sibyte/sb_zbbus.c b/sys/mips/sibyte/sb_zbbus.c
index bede7963168f..cd1685648968 100644
--- a/sys/mips/sibyte/sb_zbbus.c
+++ b/sys/mips/sibyte/sb_zbbus.c
@@ -24,6 +24,9 @@
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@@ -31,21 +34,29 @@
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/resource.h>
#include <machine/intr_machdep.h>
#include "sb_scd.h"
-__FBSDID("$FreeBSD$");
-
static MALLOC_DEFINE(M_INTMAP, "sb1250 intmap", "Sibyte 1250 Interrupt Mapper");
-#define NUM_HARD_IRQS 6
+static struct mtx zbbus_intr_mtx;
+MTX_SYSINIT(zbbus_intr_mtx, &zbbus_intr_mtx, "zbbus_intr_mask/unmask lock",
+ MTX_SPIN);
+
+/*
+ * This array holds the mapping between a MIPS hard interrupt and the
+ * interrupt sources that feed into that it.
+ */
+static uint64_t hardint_to_intsrc_mask[NHARD_IRQS];
struct sb_intmap {
int intsrc; /* interrupt mapper register number (0 - 63) */
- int hardint; /* cpu interrupt from 0 to NUM_HARD_IRQS - 1 */
+ int hardint; /* cpu interrupt from 0 to NHARD_IRQS - 1 */
/*
* The device that the interrupt belongs to. Note that multiple
@@ -86,7 +97,7 @@ sb_intmap_add(int intrnum, device_t dev, int rid, int intsrc)
{
struct sb_intmap *map;
- KASSERT(intrnum >= 0 && intrnum < NUM_HARD_IRQS,
+ KASSERT(intrnum >= 0 && intrnum < NHARD_IRQS,
("intrnum is out of range: %d", intrnum));
map = sb_intmap_lookup(intrnum, dev, rid);
@@ -113,12 +124,18 @@ sb_intmap_activate(int intrnum, device_t dev, int rid)
{
struct sb_intmap *map;
- KASSERT(intrnum >= 0 && intrnum < NUM_HARD_IRQS,
+ KASSERT(intrnum >= 0 && intrnum < NHARD_IRQS,
("intrnum is out of range: %d", intrnum));
map = sb_intmap_lookup(intrnum, dev, rid);
if (map) {
+ /*
+ * Deliver all interrupts to CPU0.
+ */
+ mtx_lock_spin(&zbbus_intr_mtx);
+ hardint_to_intsrc_mask[intrnum] |= 1ULL << map->intsrc;
sb_enable_intsrc(0, map->intsrc);
+ mtx_unlock_spin(&zbbus_intr_mtx);
} else {
/*
* In zbbus_setup_intr() we blindly call sb_intmap_activate()
@@ -133,6 +150,52 @@ sb_intmap_activate(int intrnum, device_t dev, int rid)
}
}
+/*
+ * Replace the default interrupt mask and unmask routines in intr_machdep.c
+ * with routines that are SMP-friendly. In contrast to the default mask/unmask
+ * routines in intr_machdep.c these routines do not change the SR.int_mask bits.
+ *
+ * Instead they use the interrupt mapper to either mask or unmask all
+ * interrupt sources feeding into a particular interrupt line of the processor.
+ *
+ * This means that these routines have an identical effect irrespective of
+ * which cpu is executing them. This is important because the ithread may
+ * be scheduled to run on either of the cpus.
+ */
+static void
+zbbus_intr_mask(void *arg)
+{
+ uint64_t mask;
+ int irq;
+
+ irq = (uintptr_t)arg;
+
+ mtx_lock_spin(&zbbus_intr_mtx);
+
+ mask = sb_read_intsrc_mask(0);
+ mask |= hardint_to_intsrc_mask[irq];
+ sb_write_intsrc_mask(0, mask);
+
+ mtx_unlock_spin(&zbbus_intr_mtx);
+}
+
+static void
+zbbus_intr_unmask(void *arg)
+{
+ uint64_t mask;
+ int irq;
+
+ irq = (uintptr_t)arg;
+
+ mtx_lock_spin(&zbbus_intr_mtx);
+
+ mask = sb_read_intsrc_mask(0);
+ mask &= ~hardint_to_intsrc_mask[irq];
+ sb_write_intsrc_mask(0, mask);
+
+ mtx_unlock_spin(&zbbus_intr_mtx);
+}
+
struct zbbus_devinfo {
struct resource_list resources;
};
@@ -155,6 +218,9 @@ zbbus_attach(device_t dev)
device_printf(dev, "attached.\n");
}
+ cpu_set_hardintr_mask_func(zbbus_intr_mask);
+ cpu_set_hardintr_unmask_func(zbbus_intr_unmask);
+
bus_generic_probe(dev);
bus_enumerate_hinted_children(dev);
bus_generic_attach(dev);