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", ®, 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