svn commit: r203697 - in head/sys: conf mips/conf mips/include mips/mips mips/sibyte

Neel Natu neel at FreeBSD.org
Tue Feb 9 06:24:44 UTC 2010


Author: neel
Date: Tue Feb  9 06:24:43 2010
New Revision: 203697
URL: http://svn.freebsd.org/changeset/base/203697

Log:
  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

Added:
  head/sys/mips/conf/SWARM_SMP   (contents, props changed)
  head/sys/mips/mips/mpboot.S   (contents, props changed)
Modified:
  head/sys/conf/files.mips
  head/sys/mips/include/asm.h
  head/sys/mips/include/cpu.h
  head/sys/mips/include/hwfunc.h
  head/sys/mips/include/intr_machdep.h
  head/sys/mips/include/pcpu.h
  head/sys/mips/include/smp.h
  head/sys/mips/mips/intr_machdep.c
  head/sys/mips/mips/machdep.c
  head/sys/mips/mips/mp_machdep.c
  head/sys/mips/mips/pmap.c
  head/sys/mips/sibyte/sb_asm.S
  head/sys/mips/sibyte/sb_machdep.c
  head/sys/mips/sibyte/sb_scd.c
  head/sys/mips/sibyte/sb_scd.h
  head/sys/mips/sibyte/sb_zbbus.c

Modified: head/sys/conf/files.mips
==============================================================================
--- head/sys/conf/files.mips	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/conf/files.mips	Tue Feb  9 06:24:43 2010	(r203697)
@@ -21,6 +21,7 @@
 # ----------------------------------------------------------------------
 mips/mips/machdep.c		standard
 mips/mips/mp_machdep.c		optional smp
+mips/mips/mpboot.S		optional smp
 mips/mips/psraccess.S		standard
 # ----------------------------------------------------------------------
 # Phase 3

Added: head/sys/mips/conf/SWARM_SMP
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/conf/SWARM_SMP	Tue Feb  9 06:24:43 2010	(r203697)
@@ -0,0 +1,7 @@
+#
+# $FreeBSD$
+#
+options		SMP
+options		PRINTF_BUFR_SIZE=128
+
+include		SWARM

Modified: head/sys/mips/include/asm.h
==============================================================================
--- head/sys/mips/include/asm.h	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/include/asm.h	Tue Feb  9 06:24:43 2010	(r203697)
@@ -497,17 +497,8 @@ _C_LABEL(x):
 #define	DYNAMIC_STATUS_MASK_TOUSER(sr,scratch1)
 #endif
 
-#ifdef SMP
-	/*
-	 * FREEBSD_DEVELOPERS_FIXME
-	 * In multiprocessor case, store/retrieve the pcpu structure
-	 * address for current CPU in scratch register for fast access.
-	 */
-#error "Write GET_CPU_PCPU for SMP"
-#else
 #define	GET_CPU_PCPU(reg)		\
 	lw	reg, _C_LABEL(pcpup);
-#endif
 
 /*
  * Description of the setjmp buffer

Modified: head/sys/mips/include/cpu.h
==============================================================================
--- head/sys/mips/include/cpu.h	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/include/cpu.h	Tue Feb  9 06:24:43 2010	(r203697)
@@ -122,6 +122,8 @@
 #define	SOFT_INT_MASK		(SOFT_INT_MASK_0 | SOFT_INT_MASK_1)
 #define	HW_INT_MASK		(ALL_INT_MASK & ~SOFT_INT_MASK)
 
+#define	soft_int_mask(softintr)	(1 << ((softintr) + 8))
+#define	hard_int_mask(hardintr)	(1 << ((hardintr) + 10))
 
 /*
  * The bits in the cause register.

Modified: head/sys/mips/include/hwfunc.h
==============================================================================
--- head/sys/mips/include/hwfunc.h	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/include/hwfunc.h	Tue Feb  9 06:24:43 2010	(r203697)
@@ -47,4 +47,51 @@ unsigned platform_get_timecount(struct t
 /* For hardware specific CPU initialization */
 void platform_cpu_init(void);
 void platform_secondary_init(void);
+
+#ifdef SMP
+
+/*
+ * Spin up the AP so that it starts executing MP bootstrap entry point: mpentry
+ *
+ * Returns 0 on sucess and non-zero on failure.
+ */
+int platform_start_ap(int processor_id);
+
+/*
+ * Platform-specific initialization that needs to be done when an AP starts
+ * running. This function is called from the MP bootstrap code in mpboot.S
+ */
+void platform_init_ap(int processor_id);
+
+/*
+ * Return a plaform-specific interrrupt number that is used to deliver IPIs.
+ *
+ * This hardware interrupt is used to deliver IPIs exclusively and must
+ * not be used for any other interrupt source.
+ */
+int platform_ipi_intrnum(void);
+
+/*
+ * Trigger a IPI interrupt on 'cpuid'.
+ */
+void platform_ipi_send(int cpuid);
+
+/*
+ * Quiesce the IPI interrupt source on the current cpu.
+ */
+void platform_ipi_clear(void);
+
+/*
+ * Return the processor id.
+ *
+ * Note that this function is called in early boot when stack is not available.
+ */
+extern int platform_processor_id(void);
+
+/*
+ * Return the number of processors available on this platform.
+ */
+extern int platform_num_processors(void);
+
+#endif	/* SMP */
 #endif /* !_MACHINE_HWFUNC_H_ */

Modified: head/sys/mips/include/intr_machdep.h
==============================================================================
--- head/sys/mips/include/intr_machdep.h	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/include/intr_machdep.h	Tue Feb  9 06:24:43 2010	(r203697)
@@ -60,6 +60,16 @@ void cpu_establish_softintr(const char *
 void cpu_intr(struct trapframe *);
 
 /*
+ * Allow a platform to override the default hard interrupt mask and unmask
+ * functions. The 'arg' can be cast safely to an 'int' and holds the mips
+ * hard interrupt number to mask or unmask.
+ */
+typedef void (*cpu_intr_mask_t)(void *arg);
+typedef void (*cpu_intr_unmask_t)(void *arg);
+void cpu_set_hardintr_mask_func(cpu_intr_mask_t func);
+void cpu_set_hardintr_unmask_func(cpu_intr_unmask_t func);
+
+/*
  * Opaque datatype that represents intr counter
  */
 typedef unsigned long* mips_intrcnt_t;

Modified: head/sys/mips/include/pcpu.h
==============================================================================
--- head/sys/mips/include/pcpu.h	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/include/pcpu.h	Tue Feb  9 06:24:43 2010	(r203697)
@@ -55,6 +55,13 @@ extern struct pcpu *pcpup;
 #define	PCPU_SET(member,value)	(PCPUP->pc_ ## member = (value))
 #define PCPU_LAZY_INC(member)   (++PCPUP->pc_ ## member)
 
+#ifdef SMP
+/*
+ * Instantiate the wired TLB entry at PCPU_TLB_ENTRY to map 'pcpu' at 'pcpup'.
+ */
+void	mips_pcpu_tlb_init(struct pcpu *pcpu);
+#endif
+
 #endif	/* _KERNEL */
 
 #endif	/* !_MACHINE_PCPU_H_ */

Modified: head/sys/mips/include/smp.h
==============================================================================
--- head/sys/mips/include/smp.h	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/include/smp.h	Tue Feb  9 06:24:43 2010	(r203697)
@@ -20,7 +20,6 @@
 /*
  * Interprocessor interrupts for SMP.
  */
-#define	IPI_INVLTLB		0x0001
 #define	IPI_RENDEZVOUS		0x0002
 #define	IPI_AST			0x0004
 #define	IPI_STOP		0x0008
@@ -28,13 +27,9 @@
 
 #ifndef LOCORE
 
-extern u_int32_t		boot_cpu_id;
-
-void	ipi_selected(u_int cpus, u_int32_t ipi);
-void	ipi_all_but_self(u_int32_t ipi);
-intrmask_t	smp_handle_ipi(struct trapframe *frame);
+void	ipi_selected(cpumask_t cpus, int ipi);
 void	smp_init_secondary(u_int32_t cpuid);
-void	mips_ipi_send(int thread_id);
+void	mpentry(void);
 
 #endif /* !LOCORE */
 #endif /* _KERNEL */

Modified: head/sys/mips/mips/intr_machdep.c
==============================================================================
--- head/sys/mips/mips/intr_machdep.c	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/mips/intr_machdep.c	Tue Feb  9 06:24:43 2010	(r203697)
@@ -50,6 +50,9 @@ static mips_intrcnt_t mips_intr_counters
 
 static int intrcnt_index;
 
+static cpu_intr_mask_t		hardintr_mask_func;
+static cpu_intr_unmask_t	hardintr_unmask_func;
+
 mips_intrcnt_t
 mips_intrcnt_create(const char* name)
 {
@@ -128,38 +131,54 @@ cpu_init_interrupts()
 }
 
 void
+cpu_set_hardintr_mask_func(cpu_intr_mask_t func)
+{
+
+	hardintr_mask_func = func;
+}
+
+void
+cpu_set_hardintr_unmask_func(cpu_intr_unmask_t func)
+{
+
+	hardintr_unmask_func = func;
+}
+
+void
 cpu_establish_hardintr(const char *name, driver_filter_t *filt,
     void (*handler)(void*), void *arg, int irq, int flags, void **cookiep)
 {
 	struct intr_event *event;
 	int error;
 
-#if 0
-	printf("Establish HARD IRQ %d: filt %p handler %p arg %p\n",
-	    irq, filt, handler, arg);
-#endif
 	/*
 	 * We have 6 levels, but thats 0 - 5 (not including 6)
 	 */
 	if (irq < 0 || irq >= NHARD_IRQS)
 		panic("%s called for unknown hard intr %d", __func__, irq);
 
+	if (hardintr_mask_func == NULL)
+		hardintr_mask_func = mips_mask_hard_irq;
+
+	if (hardintr_unmask_func == NULL)
+		hardintr_unmask_func = mips_unmask_hard_irq;
+
 	event = hardintr_events[irq];
 	if (event == NULL) {
 		error = intr_event_create(&event, (void *)(uintptr_t)irq, 0,
-		    irq, mips_mask_hard_irq, mips_unmask_hard_irq,
+		    irq, hardintr_mask_func, hardintr_unmask_func,
 		    NULL, NULL, "int%d", irq);
 		if (error)
 			return;
 		hardintr_events[irq] = event;
+		mips_unmask_hard_irq((void*)(uintptr_t)irq);
 	}
 
 	intr_event_add_handler(event, name, filt, handler, arg,
 	    intr_priority(flags), flags, cookiep);
 
-	mips_intrcnt_setname(mips_intr_counters[NSOFT_IRQS + irq], event->ie_fullname);
-
-	mips_unmask_hard_irq((void*)(uintptr_t)irq);
+	mips_intrcnt_setname(mips_intr_counters[NSOFT_IRQS + irq],
+			     event->ie_fullname);
 }
 
 void
@@ -185,14 +204,13 @@ cpu_establish_softintr(const char *name,
 		if (error)
 			return;
 		softintr_events[irq] = event;
+		mips_unmask_soft_irq((void*)(uintptr_t)irq);
 	}
 
 	intr_event_add_handler(event, name, filt, handler, arg,
 	    intr_priority(flags), flags, cookiep);
 
 	mips_intrcnt_setname(mips_intr_counters[irq], event->ie_fullname);
-
-	mips_unmask_soft_irq((void*)(uintptr_t)irq);
 }
 
 void

Modified: head/sys/mips/mips/machdep.c
==============================================================================
--- head/sys/mips/mips/machdep.c	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/mips/machdep.c	Tue Feb  9 06:24:43 2010	(r203697)
@@ -133,11 +133,7 @@ vm_offset_t kstack0;
 char pcpu_space[MAXCPU][PAGE_SIZE * 2] \
 	__aligned(PAGE_SIZE * 2) __section(".data");
 
-#ifdef SMP
-struct pcpu *pcpup = 0;		/* initialized in pmap_bootstrap() */
-#else
 struct pcpu *pcpup = (struct pcpu *)pcpu_space;
-#endif
 
 vm_offset_t phys_avail[PHYS_AVAIL_ENTRIES + 2];
 vm_offset_t physmem_desc[PHYS_AVAIL_ENTRIES + 2];
@@ -419,22 +415,14 @@ mips_generic_reset()
 	((void(*)(void))(intptr_t)MIPS_VEC_RESET)();
 }
 
-/*
- * Initialise a struct pcpu.
- */
+#ifdef SMP
 void
-cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
+mips_pcpu_tlb_init(struct pcpu *pcpu)
 {
-#ifdef SMP
 	vm_paddr_t pa;
 	struct tlb tlb;
 	int lobits;
-#endif
-
-	pcpu->pc_next_asid = 1;
-	pcpu->pc_asid_generation = 1;
 
-#ifdef SMP
 	/*
 	 * Map the pcpu structure at the virtual address 'pcpup'.
 	 * We use a wired tlb index to do this one-time mapping.
@@ -446,6 +434,21 @@ cpu_pcpu_init(struct pcpu *pcpu, int cpu
 	tlb.tlb_lo0 = mips_paddr_to_tlbpfn(pa) | lobits;
 	tlb.tlb_lo1 = mips_paddr_to_tlbpfn(pa + PAGE_SIZE) | lobits;
 	Mips_TLBWriteIndexed(PCPU_TLB_ENTRY, &tlb);
+}
+#endif
+
+/*
+ * Initialise a struct pcpu.
+ */
+void
+cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size)
+{
+
+	pcpu->pc_next_asid = 1;
+	pcpu->pc_asid_generation = 1;
+#ifdef SMP
+	if ((vm_offset_t)pcpup >= VM_MIN_KERNEL_ADDRESS)
+		mips_pcpu_tlb_init(pcpu);
 #endif
 }
 

Modified: head/sys/mips/mips/mp_machdep.c
==============================================================================
--- head/sys/mips/mips/mp_machdep.c	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/mips/mp_machdep.c	Tue Feb  9 06:24:43 2010	(r203697)
@@ -1,124 +1,110 @@
+/*-
+ * Copyright (c) 2009 Neelkanth Natu
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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>
 __FBSDID("$FreeBSD$");
 
-#include "opt_kstack_pages.h"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/ktr.h>
 #include <sys/proc.h>
-#include <sys/cons.h>
 #include <sys/lock.h>
-#include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/kernel.h>
 #include <sys/pcpu.h>
 #include <sys/smp.h>
-#include <sys/sysctl.h>
+#include <sys/sched.h>
 #include <sys/bus.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
-#include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
 
-#include <machine/atomic.h>
 #include <machine/clock.h>
-#include <machine/md_var.h>
-#include <machine/pcb.h>
-#include <machine/pmap.h>
 #include <machine/smp.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/cache.h>
 
+static void *dpcpu;
 static struct mtx ap_boot_mtx;
-extern struct pcpu __pcpu[];
-extern int num_tlbentries;
-void mips_start_timer(void);
-static volatile int aps_ready = 0;
-
-u_int32_t boot_cpu_id;
 
+static volatile int aps_ready;
+static volatile int mp_naps;
 
-void
-cpu_mp_announce(void)
+static void
+ipi_send(struct pcpu *pc, int ipi)
 {
-}
 
-/*
- * To implement IPIs on MIPS CPU, we use the Interrupt Line 2 ( bit 4 of cause
- * register) and a bitmap to avoid redundant IPI interrupts. To interrupt a
- * set of CPUs, the sender routine runs in a ' loop ' sending interrupts to
- * all the specified CPUs. A single Mutex (smp_ipi_mtx) is used for all IPIs
- * that spinwait for delivery. This includes the following IPIs
- * IPI_RENDEZVOUS
- * IPI_INVLPG
- * IPI_INVLTLB
- * IPI_INVLRNG
- */
-
-/*
- * send an IPI to a set of cpus.
- */
-void
-ipi_selected(u_int32_t cpus, u_int ipi)
-{
-	struct pcpu *pcpu;
-	u_int cpuid, new_pending, old_pending;
+	CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi);
 
-	CTR3(KTR_SMP, "%s: cpus: %x, ipi: %x\n", __func__, cpus, ipi);
+	atomic_set_32(&pc->pc_pending_ipis, ipi);
+	platform_ipi_send(pc->pc_cpuid);
 
-	while ((cpuid = ffs(cpus)) != 0) {
-		cpuid--;
-		cpus &= ~(1 << cpuid);
-		pcpu = pcpu_find(cpuid);
-
-		if (pcpu) {
-			do {
-				old_pending = pcpu->pc_pending_ipis;
-				new_pending = old_pending | ipi;
-			} while (!atomic_cmpset_int(&pcpu->pc_pending_ipis,
-			    old_pending, new_pending));	
-
-			if (old_pending)
-				continue;
-
-			mips_ipi_send (cpuid);
-		}
-	}
+	CTR1(KTR_SMP, "%s: sent", __func__);
 }
 
-/*
- * send an IPI to all CPUs EXCEPT myself
- */
+/* Send an IPI to a set of cpus. */
 void
-ipi_all_but_self(u_int ipi)
+ipi_selected(cpumask_t cpus, int ipi)
 {
+	struct pcpu *pc;
+
+	CTR3(KTR_SMP, "%s: cpus: %x, ipi: %x\n", __func__, cpus, ipi);
 
-	ipi_selected(PCPU_GET(other_cpus), ipi);
+	SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
+		if ((cpus & pc->pc_cpumask) != 0)
+			ipi_send(pc, ipi);
+	}
 }
 
 /*
  * Handle an IPI sent to this processor.
  */
-intrmask_t
-smp_handle_ipi(struct trapframe *frame)
+static int
+mips_ipi_handler(void *arg)
 {
-	cpumask_t cpumask;		/* This cpu mask */
+	cpumask_t cpumask;
 	u_int	ipi, ipi_bitmap;
+	int	bit;
+
+	platform_ipi_clear();	/* quiesce the pending ipi interrupt */
 
 	ipi_bitmap = atomic_readandclear_int(PCPU_PTR(pending_ipis));
-	cpumask = PCPU_GET(cpumask);
+	if (ipi_bitmap == 0)
+		return (FILTER_STRAY);
 
 	CTR1(KTR_SMP, "smp_handle_ipi(), ipi_bitmap=%x", ipi_bitmap);
-	while (ipi_bitmap) {
-		/*
-		 * Find the lowest set bit.
-		 */
-		ipi = ipi_bitmap & ~(ipi_bitmap - 1);
+
+	while ((bit = ffs(ipi_bitmap))) {
+		bit = bit - 1;
+		ipi = 1 << bit;
 		ipi_bitmap &= ~ipi;
 		switch (ipi) {
-		case IPI_INVLTLB:
-			CTR0(KTR_SMP, "IPI_INVLTLB");
-			break;
-
 		case IPI_RENDEZVOUS:
 			CTR0(KTR_SMP, "IPI_RENDEZVOUS");
 			smp_rendezvous_action();
@@ -129,51 +115,136 @@ smp_handle_ipi(struct trapframe *frame)
 			break;
 
 		case IPI_STOP:
-
 			/*
 			 * IPI_STOP_HARD is mapped to IPI_STOP so it is not
 			 * necessary to add it in the switch.
 			 */
 			CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
+			cpumask = PCPU_GET(cpumask);
 			atomic_set_int(&stopped_cpus, cpumask);
-
 			while ((started_cpus & cpumask) == 0)
-			    ;
+				cpu_spinwait();
 			atomic_clear_int(&started_cpus, cpumask);
 			atomic_clear_int(&stopped_cpus, cpumask);
+			CTR0(KTR_SMP, "IPI_STOP (restart)");
 			break;
+		default:
+			panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu);
 		}
 	}
-	return CR_INT_IPI;
+
+	return (FILTER_HANDLED);
+}
+
+static int
+start_ap(int cpuid)
+{
+	int cpus, ms;
+
+	cpus = mp_naps;
+	dpcpu = (void *)kmem_alloc(kernel_map, DPCPU_SIZE);
+
+	if (platform_start_ap(cpuid) != 0)
+		return (-1);			/* could not start AP */
+
+	for (ms = 0; ms < 5000; ++ms) {
+		if (mp_naps > cpus)
+			return (0);		/* success */
+		else
+			DELAY(1000);
+	}
+
+	return (-2);				/* timeout initializing AP */
 }
 
 void
 cpu_mp_setmaxid(void)
 {
 
-	mp_maxid = MAXCPU - 1;
+	mp_ncpus = platform_num_processors();
+	if (mp_ncpus <= 0)
+		mp_ncpus = 1;
+
+	mp_maxid = min(mp_ncpus, MAXCPU) - 1;
+}
+
+void
+cpu_mp_announce(void)
+{
+	/* NOTHING */
+}
+
+struct cpu_group *
+cpu_topo(void)
+{
+
+	return (smp_topo_none());
+}
+
+int
+cpu_mp_probe(void)
+{
+
+	return (mp_ncpus > 1);
+}
+
+void
+cpu_mp_start(void)
+{
+	int error, cpuid;
+
+	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
+
+	all_cpus = 1;		/* BSP */
+	for (cpuid = 1; cpuid < platform_num_processors(); ++cpuid) {
+		if (cpuid >= MAXCPU) {
+			printf("cpu_mp_start: ignoring AP #%d.\n", cpuid);
+			continue;
+		}
+
+		if ((error = start_ap(cpuid)) != 0) {
+			printf("AP #%d failed to start: %d\n", cpuid, error);
+			continue;
+		}
+		
+		if (bootverbose)
+			printf("AP #%d started!\n", cpuid);
+
+		all_cpus |= 1 << cpuid;
+	}
+
+	PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask));
 }
 
 void
 smp_init_secondary(u_int32_t cpuid)
 {
+	int ipi_int_mask, clock_int_mask;
 
-	if (cpuid >=  MAXCPU)
-		panic ("cpu id exceeds MAXCPU\n");
+	/* TLB */
+	Mips_SetWIRED(0);
+	Mips_TLBFlush(num_tlbentries);
+	Mips_SetWIRED(VMWIRED_ENTRIES);
+
+	/*
+	 * We assume that the L1 cache on the APs is identical to the one
+	 * on the BSP.
+	 */
+	mips_dcache_wbinv_all();
+	mips_icache_sync_all();
 
-	/* tlb init */
-	R4K_SetWIRED(0);
-	R4K_TLBFlush(num_tlbentries);
-	R4K_SetWIRED(VMWIRED_ENTRIES);
 	MachSetPID(0);
 
-	Mips_SyncCache();
+	pcpu_init(PCPU_ADDR(cpuid), cpuid, sizeof(struct pcpu));
+	dpcpu_init(dpcpu, cpuid);
+
+	/* The AP has initialized successfully - allow the BSP to proceed */
+	++mp_naps;
 
-	mips_cp0_status_write(0);
+	/* Spin until the BSP is ready to release the APs */
 	while (!aps_ready)
 		;
 
-	mips_sync(); mips_sync();
 	/* Initialize curthread. */
 	KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
 	PCPU_SET(curthread, PCPU_GET(idlethread));
@@ -182,15 +253,16 @@ smp_init_secondary(u_int32_t cpuid)
 
 	smp_cpus++;
 
-	CTR1(KTR_SMP, "SMP: AP CPU #%d Launched", PCPU_GET(cpuid));
+	CTR1(KTR_SMP, "SMP: AP CPU #%d launched", PCPU_GET(cpuid));
 
 	/* Build our map of 'other' CPUs. */
 	PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask));
 
-	printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid));
+	if (bootverbose)
+		printf("SMP: AP CPU #%d launched.\n", PCPU_GET(cpuid));
 
 	if (smp_cpus == mp_ncpus) {
-		smp_started = 1;
+		atomic_store_rel_int(&smp_started, 1);
 		smp_active = 1;
 	}
 
@@ -198,103 +270,46 @@ smp_init_secondary(u_int32_t cpuid)
 
 	while (smp_started == 0)
 		; /* nothing */
-	/* Enable Interrupt */
-	mips_cp0_status_write(SR_INT_ENAB);
-	/* ok, now grab sched_lock and enter the scheduler */
-	mtx_lock_spin(&sched_lock);
 
 	/*
-	 * Correct spinlock nesting.  The idle thread context that we are
-	 * borrowing was created so that it would start out with a single
-	 * spin lock (sched_lock) held in fork_trampoline().  Since we've
-	 * explicitly acquired locks in this function, the nesting count
-	 * is now 2 rather than 1.  Since we are nested, calling
-	 * spinlock_exit() will simply adjust the counts without allowing
-	 * spin lock using code to interrupt us.
+	 * Unmask the clock and ipi interrupts.
 	 */
-	spinlock_exit();
-	KASSERT(curthread->td_md.md_spinlock_count == 1, ("invalid count"));
-
-	binuptime(PCPU_PTR(switchtime));
-	PCPU_SET(switchticks, ticks);
-
-	/* kick off the clock on this cpu */
-	mips_start_timer();
-	cpu_throw(NULL, choosethread());	/* doesn't return */
-
-	panic("scheduler returned us to %s", __func__);
-}
-
-static int
-smp_start_secondary(int cpuid)
-{
-	struct pcpu *pcpu;
-	void *dpcpu;
-	int i;
-
-	if (bootverbose)
-		printf("smp_start_secondary: starting cpu %d\n", cpuid);
+	clock_int_mask = hard_int_mask(5);
+	ipi_int_mask = hard_int_mask(platform_ipi_intrnum());
+	set_intr_mask(ALL_INT_MASK & ~(ipi_int_mask | clock_int_mask));
 
-	dpcpu = (void *)kmem_alloc(kernel_map, DPCPU_SIZE);
-	pcpu_init(&__pcpu[cpuid], cpuid, sizeof(struct pcpu));
-	dpcpu_init(dpcpu, cpuid);
+	/*
+	 * Bootstrap the compare register.
+	 */
+	mips_wr_compare(mips_rd_count() + counter_freq / hz);
 
-	if (bootverbose)
-		printf("smp_start_secondary: cpu %d started\n", cpuid);
+	enableintr();
 
-	return 1;
-}
+	/* enter the scheduler */
+	sched_throw(NULL);
 
-int
-cpu_mp_probe(void)
-{
-	int i, cpus;
-
-	/* XXX: Need to check for valid platforms here. */
-
-	boot_cpu_id = PCPU_GET(cpuid);
-	KASSERT(boot_cpu_id == 0, ("cpu_mp_probe() called on non-primary CPU"));
-	all_cpus = PCPU_GET(cpumask);
-	mp_ncpus = 1;
-
-	/* Make sure we have at least one secondary CPU. */
-	cpus = 0;
-	for (i = 0; i < MAXCPU; i++) {
-		cpus++;
-	}
-	return (cpus);
+	panic("scheduler returned us to %s", __func__);
+	/* NOTREACHED */
 }
 
-void
-cpu_mp_start(void)
+static void
+release_aps(void *dummy __unused)
 {
-	int i, cpuid;
-
-	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
+	int ipi_irq;
 
-	cpuid = 1;
-	for (i = 0; i < MAXCPU; i++) {
+	if (mp_ncpus == 1)
+		return;
 
-		if (i == boot_cpu_id)
-			continue;
-		if (smp_start_secondary(i)) {
-			all_cpus |= (1 << cpuid);
-			mp_ncpus++;
-		cpuid++;
-		}
-	}
-	idle_mask |= CR_INT_IPI;
-	PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask));
-}
+	/*
+	 * IPI handler
+	 */
+	ipi_irq = platform_ipi_intrnum();
+	cpu_establish_hardintr("ipi", mips_ipi_handler, NULL, NULL, ipi_irq,
+			       INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, NULL);
 
-static void
-release_aps(void *dummy __unused)
-{
-	if (bootverbose && mp_ncpus > 1)
-		printf("%s: releasing secondary CPUs\n", __func__);
 	atomic_store_rel_int(&aps_ready, 1);
 
-	while (mp_ncpus > 1 && smp_started == 0)
+	while (smp_started == 0)
 		; /* nothing */
 }
 

Added: head/sys/mips/mips/mpboot.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mips/mpboot.S	Tue Feb  9 06:24:43 2010	(r203697)
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2010 Neelkanth Natu
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/asm.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+
+#include "assym.s"
+
+	.text
+	.set	noat
+	.set	noreorder
+
+GLOBAL(mpentry)
+	mtc0	zero, COP_0_STATUS_REG	/* disable interrupts */
+
+	mtc0	zero, COP_0_CAUSE_REG	/* clear soft interrupts */
+
+	li	t0, CFG_K0_CACHED	/* make sure kseg0 is cached */
+	mtc0	t0, MIPS_COP_0_CONFIG
+	COP0_SYNC
+
+	jal	platform_processor_id	/* get the processor number */
+	nop
+	move	s0, v0
+
+	/*
+	 * Initialize stack and call machine startup
+	 */
+	PTR_LA	sp, _C_LABEL(pcpu_space)
+	addiu	sp, (NBPG * 2) - START_FRAME
+	sll	t0, s0, PAGE_SHIFT + 1
+	addu	sp, sp, t0
+
+	/* Zero out old ra and old fp for debugger */
+	sw      zero, START_FRAME - 4(sp)
+	sw      zero, START_FRAME - 8(sp)
+
+	PTR_LA	gp, _C_LABEL(_gp)
+
+	jal	platform_init_ap
+	move	a0, s0
+
+	jal	smp_init_secondary
+	move	a0, s0
+
+	PANIC("AP startup failed!")

Modified: head/sys/mips/mips/pmap.c
==============================================================================
--- head/sys/mips/mips/pmap.c	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/mips/pmap.c	Tue Feb  9 06:24:43 2010	(r203697)
@@ -362,6 +362,15 @@ again:
 	virtual_avail = roundup2(virtual_avail, PAGE_SIZE * 2);
 	pcpup = (struct pcpu *)virtual_avail;
 	virtual_avail += PAGE_SIZE * 2;
+
+	/*
+	 * Initialize the wired TLB entry mapping the pcpu region for
+	 * the BSP at 'pcpup'. Up until this point we were operating
+	 * with the 'pcpup' for the BSP pointing to a virtual address
+	 * in KSEG0 so there was no need for a TLB mapping.
+	 */
+	mips_pcpu_tlb_init(PCPU_ADDR(0));
+
 	if (bootverbose)
 		printf("pcpu is available at virtual address %p.\n", pcpup);
 #endif

Modified: head/sys/mips/sibyte/sb_asm.S
==============================================================================
--- head/sys/mips/sibyte/sb_asm.S	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/sibyte/sb_asm.S	Tue Feb  9 06:24:43 2010	(r203697)
@@ -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 */

Modified: head/sys/mips/sibyte/sb_machdep.c
==============================================================================
--- head/sys/mips/sibyte/sb_machdep.c	Tue Feb  9 05:52:35 2010	(r203696)
+++ head/sys/mips/sibyte/sb_machdep.c	Tue Feb  9 06:24:43 2010	(r203697)
@@ -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));
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list