PERFORCE change 229692 for review

Brooks Davis brooks at FreeBSD.org
Thu Jun 13 22:17:50 UTC 2013


http://p4web.freebsd.org/@@229692?ac=10

Change 229692 by brooks at brooks_zenith on 2013/06/13 22:17:45

	Checkpoint a compiling, but untested SMP implementation for BERI.
	
	In principle, the included kernel config will only find one CPU
	in the FDT and will boot with that.

Affected files ...

.. //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_ic_if.m#3 edit
.. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_asm.S#2 edit
.. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_mp.c#2 edit
.. //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_pic.c#5 edit
.. //depot/projects/ctsrd/beribsd/src/sys/mips/conf/BERI_SIM_SMP_MDROOT#1 add

Differences ...

==== //depot/projects/ctsrd/beribsd/src/sys/dev/fdt/fdt_ic_if.m#3 (text+ko) ====

@@ -225,3 +225,42 @@
 	device_t	_child;
 	u_int		_irq;
 };
+
+/**
+ * @brief Enable an IPI source.
+ *
+ * @param _dev		the interrupt controller
+ * @param _tid		the thread ID (relative to the interrupt controller)
+ *			to enable IPIs for
+ * @param _ipi_irq	hardware IRQ to send IPIs to
+ */
+METHOD void setup_ipi {
+	device_t	_dev;
+	u_int		_tid;
+	u_int		_irq;
+};
+
+/**
+ * @brief Send an IPI to the specified thread.
+ *
+ * @param _dev		the interrupt controller
+ * @param _tid		the thread ID (relative to the interrupt controller)
+ *			to send IPIs to
+ */
+METHOD void send_ipi {
+	device_t	_dev;
+	u_int		_tid;
+};
+
+/**
+ * @brief Clear the IPI on the specfied thread.  Only call with the
+ * local hardware thread or interrupts may be lost!
+ *
+ * @param _dev		the interrupt controller
+ * @param _tid		the thread ID (relative to the interrupt controller)
+ *			to clear the IPI on
+ */
+METHOD void clear_ipi {
+	device_t	_dev;
+	u_int		_tid;
+};

==== //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_asm.S#2 (text+ko) ====

@@ -32,10 +32,11 @@
 #include <machine/cpuregs.h>
 
 #ifdef SMP
+/* XXXBED: Correct for multithread, needs adjustment for multicore. */
 LEAF(platform_processor_id)
 	MFC0	v0, MIPS_COP_0_PRID
-	srl	v0, v0, 25
+	srl	v0, v0, 24
 	jr	ra
-	and	v0, v0, 7
+	and	v0, v0, 255
 END(platform_processor_id)
 #endif

==== //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_mp.c#2 (text+ko) ====

@@ -36,40 +36,84 @@
 #include <sys/smp.h>
 
 #include <machine/hwfunc.h>
+#include <machine/smp.h>
+
+#include <dev/fdt/fdt_common.h>
+#include "fdt_ic_if.h"
 
-/*
- * XXXRW:
- *
- * 1. It would be nice if we could read the number of hardware threads present
- * on the current CPU core from a CP0 register (or similar).
- */
+struct spin_entry {
+	uint64_t entry_addr;
+	uint64_t a0;
+	uint32_t rsvd1;
+	uint32_t pir;
+	uint64_t rsvd2;
+};
 
-#define	BERI_NUMTHREADS	8
+static phandle_t cpu_of_nodes[MAXCPU];
+static device_t picmap[MAXCPU];
 
 void
 platform_cpu_mask(cpuset_t *mask)
 {
-        u_int i;
+	phandle_t cpus, cpu;
+	pcell_t reg;
+
+	if ((cpus = OF_finddevice("/cpus")) <= 0) {
+		printf("%s: no \"/cpus\" device found in FDT\n", __func__);
+		goto error;
+	}
+	if ((cpu = OF_child(cpus)) <= 0) {
+		printf("%s: no children of \"/cpus\" found in FDT\n", __func__);
+		goto error;
+	}
+        CPU_ZERO(mask);
+	do {
+		if (OF_getprop(cpu, "reg", &reg, sizeof(reg)) <= 0) {
+			printf("%s: cpu device with no reg property\n",
+			    __func__);
+			goto error;
+		}
+		if (reg > MAXCPU) {
+			printf("%s: cpu ID too large (%d > %d)\n", __func__,
+			     reg, MAXCPU);
+		}
+		cpu_of_nodes[reg] = cpu;
+			
+		CPU_SET(reg, mask);
+	} while ((cpu = OF_peer(cpu)) > 0);
+	return;
 
+error:
+	/*
+	 * If we run into any problems determining the CPU layout,
+	 * fall back to UP.
+	 *
+	 * XXX: panic instead?
+	 */
         CPU_ZERO(mask);
-        for (i = 0; i < BERI_NUMTHREADS; i++)
-                CPU_SET(i, mask);
+	CPU_SET(1, mask);
 }
 
 void
 platform_ipi_send(int cpuid)
 {
 
-	panic("%s: not yet", __func__);
+	/* XXX: single core/pic */
+	FDT_IC_SEND_IPI(picmap[cpuid], cpuid);
 }
 
 void
 platform_ipi_clear(void)
 {
+	int cpuid = platform_processor_id();
 
-	panic("%s: not yet", __func__);
+	/* XXX: single core/pic */
+	FDT_IC_CLEAR_IPI(picmap[cpuid], cpuid);
 }
 
+/*
+ * XXXBED: Set via FDT?
+ */
 int
 platform_ipi_intrnum(void)
 {
@@ -77,6 +121,9 @@
 	return (4);
 }
 
+/*
+ * XXXBED: Fine for MT, will need something better for multi-core.
+ */
 struct cpu_group *
 platform_smp_topo(void)
 {
@@ -88,8 +135,9 @@
 platform_init_ap(int cpuid)
 {
 	u_int clock_int_mask;
+	device_t ic;
 
-	KASSERT(cpuid != 0, ("%s: invalid CPU id %d", __func__, cpuid));
+	KASSERT(cpuid < MAXCPU, ("%s: invalid CPU id %d", __func__, cpuid));
 
 	/*
 	 * Enable per-thread timer.
@@ -97,18 +145,54 @@
 	clock_int_mask = hard_int_mask(5);
 	set_intr_mask(clock_int_mask);
 
-#ifdef NOTYET
 	/*
 	 * Enable IPIs.
 	 */
-	 * XXXRW: Not yet.
-	 */
-#endif
+	/* XXX: single core/pic */
+	ic = SLIST_FIRST(&fdt_ic_list_head)->dev;
+	FDT_IC_SETUP_IPI(ic, cpuid, platform_ipi_intrnum());
+	picmap[cpuid] = ic;
 }
 
+/*
+ * BERI startup conforms to the spin-table start method defined in the
+ * ePAPR 1.0 spec.  The initial spin waiting for an address is started
+ * by the CPU firmware.
+ */
 int
 platform_start_ap(int cpuid)
 {
+	phandle_t cpu;
+	char prop[16];
+	struct spin_entry *se;
 
-	panic("%s: not yet", __func__);
+	KASSERT(cpuid != 0, ("%s: can't start CPU 0!\n", __func__));
+	KASSERT((cpuid > 0 && cpuid < MAXCPU),
+	    ("%s: invalid CPU id %d", __func__, cpuid));
+	
+	cpu = cpu_of_nodes[cpuid];
+	if (OF_getprop(cpu, "status", &prop, sizeof(prop)) <= 0 &&
+	    OF_getprop(OF_parent(cpu), "status", &prop, sizeof(prop)))
+		panic("%s: CPU %d has no status property", __func__, cpuid);
+	else
+		if (strcmp("disabled", prop) != 0)
+			panic("%s: CPU %d status is '%s' not 'disabled'",
+			    __func__, cpuid, prop);
+	
+	if (OF_getprop(cpu, "enable-method", &prop, sizeof(prop)) <= 0 &&
+	    OF_getprop(OF_parent(cpu), "enable-method", &prop, sizeof(prop)))
+		panic("%s: CPU %d has no enable-method property", __func__,
+		    cpuid);
+	else
+		if (strcmp("spin-table", prop) != 0)
+			panic("%s: CPU %d enable-method is '%s' not "
+			    "'spin-table'", __func__, cpuid, prop);
+
+	if (OF_getprop(cpu, "cpu-release-addr", &se, sizeof(se)) <= 0)
+		panic("%s: CPU %d has missing or invalid cpu-release-addr",
+		    __func__, cpuid);
+	se->pir = cpuid;
+	se->entry_addr = (intptr_t)mpentry;
+
+	return (0);
 }

==== //depot/projects/ctsrd/beribsd/src/sys/mips/beri/beri_pic.c#5 (text+ko) ====

@@ -79,6 +79,7 @@
 static void	beripic_intr(void *);
 
 #define	BP_MAX_HARD_IRQS	6
+#define	BP_FIRST_SOFT		64
 
 struct beripic_softc {
 	device_t		bp_dev;
@@ -127,7 +128,6 @@
 #ifdef __mips__
 	mips_intrcnt_t		counter;
 #endif
-	/* XXX counter */
 };
 
 struct beripic_cookie {
@@ -381,6 +381,9 @@
 	sc->bp_nhard = nhard;
 	sc->bp_nsoft = nsoft;
 	sc->bp_nsrcs = sc->bp_nhard + sc->bp_nsoft;
+	/* XXX: should deal with gap between hard and soft */
+	KASSERT(sc->bp_nhard < BP_FIRST_SOFT,
+	    ("too many hard sources"));
 	KASSERT(rman_get_size(sc->bp_cfg_res) / 8 == sc->bp_nsrcs,
 	    ("config space size does not match sources"));
 	KASSERT(sc->bp_nhard % 64 == 0,
@@ -627,6 +630,45 @@
 	bpic->intr(bpic->arg);
 }
 
+#ifdef SMP
+static void
+beripic_setup_ipi(device_t ic, u_int tid, u_int ipi_irq)
+{
+	
+	bp_config_source(ic, BP_FIRST_SOFT + tid, 1, tid, ipi_irq);
+}
+
+static void
+beripic_send_ipi(device_t ic, u_int tid)
+{
+	struct beripic_softc *sc;
+	uint64_t bit;
+
+	sc = device_get_softc(ic);
+
+	KASSERT(tid < sc->bp_nsoft, ("tid (%d) to large\n"));
+
+	bit = 1ULL << (tid % 64);
+	bus_space_write_8(sc->bp_set_bst, sc->bp_set_bsh, 
+	    BP_FIRST_SOFT / 8 + (tid >> 6), bit);
+}
+
+static void
+beripic_clear_ipi(device_t ic, u_int tid)
+{
+	struct beripic_softc *sc;
+	uint64_t bit;
+
+	sc = device_get_softc(ic);
+
+	KASSERT(tid < sc->bp_nsoft, ("tid (%d) to large\n"));
+
+	bit = 1ULL << (tid % 64);
+	bus_space_write_8(sc->bp_clear_bst, sc->bp_clear_bsh, 
+	    BP_FIRST_SOFT / 8 + (tid >> 6), bit);
+}
+#endif
+
 devclass_t	beripic_devclass;
 
 static device_method_t beripic_fdt_methods[] = {
@@ -642,6 +684,12 @@
 	DEVMETHOD(fdt_ic_setup_intr,	beripic_setup_intr),
 	DEVMETHOD(fdt_ic_teardown_intr,	beripic_teardown_intr),
 
+#ifdef SMP
+	DEVMETHOD(fdt_ic_setup_ipi,	beripic_setup_ipi),
+	DEVMETHOD(fdt_ic_clear_ipi,	beripic_clear_ipi),
+	DEVMETHOD(fdt_ic_send_ipi,	beripic_send_ipi),
+#endif
+
 	{ 0, 0 },
 };
 


More information about the p4-projects mailing list