summaryrefslogtreecommitdiffstats
path: root/sys/mips/sibyte
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2010-02-09 06:24:43 +0000
committerneel <neel@FreeBSD.org>2010-02-09 06:24:43 +0000
commit91212ae23c60e92beb6a2bf31304fe0f44d84cee (patch)
tree6b8fc2551b36316f7e2c7437b3ef3de98dbabfb2 /sys/mips/sibyte
parent764ce56acec6e1b162434305a36821de3b6e3ded (diff)
downloadFreeBSD-src-91212ae23c60e92beb6a2bf31304fe0f44d84cee.zip
FreeBSD-src-91212ae23c60e92beb6a2bf31304fe0f44d84cee.tar.gz
SMP support for the mips port.
The platform that supports SMP currently is a SWARM with a dual-core Sibyte processor. The kernel config file to use is SWARM_SMP. Reviewed by: imp, rrs
Diffstat (limited to 'sys/mips/sibyte')
-rw-r--r--sys/mips/sibyte/sb_asm.S18
-rw-r--r--sys/mips/sibyte/sb_machdep.c75
-rw-r--r--sys/mips/sibyte/sb_scd.c42
-rw-r--r--sys/mips/sibyte/sb_scd.h6
-rw-r--r--sys/mips/sibyte/sb_zbbus.c78
5 files changed, 212 insertions, 7 deletions
diff --git a/sys/mips/sibyte/sb_asm.S b/sys/mips/sibyte/sb_asm.S
index b81c067..19d00dd 100644
--- a/sys/mips/sibyte/sb_asm.S
+++ b/sys/mips/sibyte/sb_asm.S
@@ -27,6 +27,7 @@
*/
#include <machine/asm.h>
+#include <machine/cpuregs.h>
/*
* We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit
@@ -80,3 +81,20 @@ LEAF(sb_store64)
jr ra
sd t0, 0(a0)
END(sb_store64)
+
+#ifdef SMP
+/*
+ * This function must be implemented in assembly because it is called early
+ * in AP boot without a valid stack.
+ *
+ * This cpu number is available in bits 25 to 27 of the coprocessor 0 PRID
+ * register. This is not documented in the BCM1250 user manual but can be
+ * gleaned from the CFE source code - see sb1250_altcpu.S
+ */
+LEAF(platform_processor_id)
+ mfc0 v0, MIPS_COP_0_PRID
+ srl v0, v0, 25
+ jr ra
+ and v0, v0, 7
+END(platform_processor_id)
+#endif /* SMP */
diff --git a/sys/mips/sibyte/sb_machdep.c b/sys/mips/sibyte/sb_machdep.c
index c544b18..c6043b8 100644
--- a/sys/mips/sibyte/sb_machdep.c
+++ b/sys/mips/sibyte/sb_machdep.c
@@ -74,6 +74,10 @@ __FBSDID("$FreeBSD$");
#include <machine/trap.h>
#include <machine/vmparam.h>
+#ifdef SMP
+#include <machine/smp.h>
+#endif
+
#ifdef CFE
#include <dev/cfe/cfe_api.h>
#endif
@@ -114,6 +118,19 @@ sb_intr_init(int cpuid)
intrnum = sb_route_intsrc(intsrc);
sb_disable_intsrc(cpuid, intsrc);
sb_write_intmap(cpuid, intsrc, intrnum);
+#ifdef SMP
+ /*
+ * Set up the mailbox interrupt mapping.
+ *
+ * The mailbox interrupt is "special" in that it is not shared
+ * with any other interrupt source.
+ */
+ if (intsrc == INTSRC_MAILBOX3) {
+ intrnum = platform_ipi_intrnum();
+ sb_write_intmap(cpuid, INTSRC_MAILBOX3, intrnum);
+ sb_enable_intsrc(cpuid, INTSRC_MAILBOX3);
+ }
+#endif
}
}
@@ -282,6 +299,64 @@ kseg0_map_coherent(void)
mips_wr_config(config);
}
+#ifdef SMP
+void
+platform_ipi_send(int cpuid)
+{
+ KASSERT(cpuid == 0 || cpuid == 1,
+ ("platform_ipi_send: invalid cpuid %d", cpuid));
+
+ sb_set_mailbox(cpuid, 1ULL);
+}
+
+void
+platform_ipi_clear(void)
+{
+ int cpuid;
+
+ cpuid = PCPU_GET(cpuid);
+ sb_clear_mailbox(cpuid, 1ULL);
+}
+
+int
+platform_ipi_intrnum(void)
+{
+
+ return (4);
+}
+
+void
+platform_init_ap(int cpuid)
+{
+
+ KASSERT(cpuid == 1, ("AP has an invalid cpu id %d", cpuid));
+
+ /*
+ * Make sure that kseg0 is mapped cacheable-coherent
+ */
+ kseg0_map_coherent();
+
+ sb_intr_init(cpuid);
+}
+
+int
+platform_start_ap(int cpuid)
+{
+#ifdef CFE
+ int error;
+
+ if ((error = cfe_cpu_start(cpuid, mpentry, 0, 0, 0))) {
+ printf("cfe_cpu_start error: %d\n", error);
+ return (-1);
+ } else {
+ return (0);
+ }
+#else
+ return (-1);
+#endif /* CFE */
+}
+#endif /* SMP */
+
void
platform_start(__register_t a0, __register_t a1, __register_t a2,
__register_t a3)
diff --git a/sys/mips/sibyte/sb_scd.c b/sys/mips/sibyte/sb_scd.c
index c499822..007e149 100644
--- a/sys/mips/sibyte/sb_scd.c
+++ b/sys/mips/sibyte/sb_scd.c
@@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <machine/resource.h>
-#include <machine/intr_machdep.h>
+#include <machine/hwfunc.h>
#include "sb_scd.h"
@@ -189,11 +189,51 @@ sb_route_intsrc(int intsrc)
* Interrupt 5 is used by sources internal to the CPU (e.g. timer).
* Use a deterministic mapping for the remaining sources.
*/
+#ifdef SMP
+ KASSERT(platform_ipi_intrnum() == 4,
+ ("Unexpected interrupt number used for IPI"));
+ intrnum = intsrc % 4;
+#else
intrnum = intsrc % 5;
+#endif
return (intrnum);
}
+#ifdef SMP
+static uint64_t
+sb_read_sysrev(void)
+{
+
+ return (sb_load64(SYSREV_ADDR));
+}
+
+void
+sb_set_mailbox(int cpu, uint64_t val)
+{
+ uint32_t regaddr;
+
+ regaddr = MAILBOX_SET_ADDR(cpu);
+ sb_store64(regaddr, val);
+}
+
+void
+sb_clear_mailbox(int cpu, uint64_t val)
+{
+ uint32_t regaddr;
+
+ regaddr = MAILBOX_CLEAR_ADDR(cpu);
+ sb_store64(regaddr, val);
+}
+
+int
+platform_num_processors(void)
+{
+
+ return (SYSREV_NUM_PROCESSORS(sb_read_sysrev()));
+}
+#endif /* SMP */
+
#define SCD_PHYSADDR 0x10000000
#define SCD_SIZE 0x00060000
diff --git a/sys/mips/sibyte/sb_scd.h b/sys/mips/sibyte/sb_scd.h
index 8f60716..03d2681 100644
--- a/sys/mips/sibyte/sb_scd.h
+++ b/sys/mips/sibyte/sb_scd.h
@@ -42,4 +42,10 @@ void sb_write_intsrc_mask(int cpu, uint64_t mask);
void sb_write_intmap(int cpu, int intsrc, int intrnum);
int sb_read_intmap(int cpu, int intsrc);
+#ifdef SMP
+#define INTSRC_MAILBOX3 29
+void sb_set_mailbox(int cpuid, uint64_t val);
+void sb_clear_mailbox(int cpuid, uint64_t val);
+#endif
+
#endif /* _SB_SCD_H_ */
diff --git a/sys/mips/sibyte/sb_zbbus.c b/sys/mips/sibyte/sb_zbbus.c
index bede796..cd16856 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);
OpenPOWER on IntegriCloud