diff options
author | Neel Natu <neel@FreeBSD.org> | 2010-02-09 06:24:43 +0000 |
---|---|---|
committer | Neel Natu <neel@FreeBSD.org> | 2010-02-09 06:24:43 +0000 |
commit | 1d4fd9f5a87fab90b577391f0417ce050fd8ca63 (patch) | |
tree | 6b8fc2551b36316f7e2c7437b3ef3de98dbabfb2 /sys/mips/sibyte | |
parent | 90b4621a5f550931cc32ac2fa9d1ea771a8134af (diff) | |
download | src-1d4fd9f5a87fab90b577391f0417ce050fd8ca63.tar.gz src-1d4fd9f5a87fab90b577391f0417ce050fd8ca63.zip |
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
Notes
Notes:
svn path=/head/; revision=203697
Diffstat (limited to 'sys/mips/sibyte')
-rw-r--r-- | sys/mips/sibyte/sb_asm.S | 18 | ||||
-rw-r--r-- | sys/mips/sibyte/sb_machdep.c | 75 | ||||
-rw-r--r-- | sys/mips/sibyte/sb_scd.c | 42 | ||||
-rw-r--r-- | sys/mips/sibyte/sb_scd.h | 6 | ||||
-rw-r--r-- | sys/mips/sibyte/sb_zbbus.c | 78 |
5 files changed, 212 insertions, 7 deletions
diff --git a/sys/mips/sibyte/sb_asm.S b/sys/mips/sibyte/sb_asm.S index b81c067ad14b..19d00dd0bc9d 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 c544b180b363..c6043b8514a3 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 c499822c68c7..007e1499c7b3 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 8f607160274a..03d26811db63 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 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); |