Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Sep 2010 16:09:46 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r212151 - in user/nwhitehorn/ps3: powerpc/aim powerpc/booke powerpc/powerpc powerpc/ps3 sys
Message-ID:  <201009021609.o82G9kJ1010454@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Thu Sep  2 16:09:46 2010
New Revision: 212151
URL: http://svn.freebsd.org/changeset/base/212151

Log:
  Bring up both threads on Cell in a useful way. This consists of several
  changes:
  - Provide a new method (based on the one on i386) to provide MD idle
    routines. These can be overridden by the hypervisor module if
    required.
  - Introduce a new mechanism to the platform KOBJ to report CPU topology.
  - Extend the PS3 hypervisor module to use the above.
  - Add IPI support to ps3pic.

Modified:
  user/nwhitehorn/ps3/powerpc/aim/machdep.c
  user/nwhitehorn/ps3/powerpc/booke/machdep.c
  user/nwhitehorn/ps3/powerpc/powerpc/cpu.c
  user/nwhitehorn/ps3/powerpc/powerpc/mp_machdep.c
  user/nwhitehorn/ps3/powerpc/powerpc/platform.c
  user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m
  user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c
  user/nwhitehorn/ps3/powerpc/ps3/ps3pic.c
  user/nwhitehorn/ps3/sys/smp.h

Modified: user/nwhitehorn/ps3/powerpc/aim/machdep.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/aim/machdep.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/aim/machdep.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -623,52 +623,6 @@ cpu_halt(void)
 	OF_exit();
 }
 
-void
-cpu_idle(int busy)
-{
-	register_t msr;
-	uint16_t vers;
-
-	msr = mfmsr();
-	vers = mfpvr() >> 16;
-
-#ifdef INVARIANTS
-	if ((msr & PSL_EE) != PSL_EE) {
-		struct thread *td = curthread;
-		printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
-		panic("ints disabled in idleproc!");
-	}
-#endif
-	if (powerpc_pow_enabled) {
-		switch (vers) {
-		case IBM970:
-		case IBM970FX:
-		case IBM970MP:
-		case MPC7447A:
-		case MPC7448:
-		case MPC7450:
-		case MPC7455:
-		case MPC7457:
-			__asm __volatile("\
-			    dssall; sync; mtmsr %0; isync"
-			    :: "r"(msr | PSL_POW));
-			break;
-		default:
-			powerpc_sync();
-			mtmsr(msr | PSL_POW);
-			isync();
-			break;
-		}
-	}
-}
-
-int
-cpu_idle_wakeup(int cpu)
-{
-
-	return (0);
-}
-
 int
 ptrace_set_pc(struct thread *td, unsigned long addr)
 {

Modified: user/nwhitehorn/ps3/powerpc/booke/machdep.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/booke/machdep.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/booke/machdep.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -468,38 +468,6 @@ cpu_flush_dcache(void *ptr, size_t len)
 	/* TBD */
 }
 
-/*
- * cpu_idle
- *
- * Set Wait state enable.
- */
-void
-cpu_idle (int busy)
-{
-	register_t msr;
-
-	msr = mfmsr();
-
-#ifdef INVARIANTS
-	if ((msr & PSL_EE) != PSL_EE) {
-		struct thread *td = curthread;
-		printf("td msr %x\n", td->td_md.md_saved_msr);
-		panic("ints disabled in idleproc!");
-	}
-#endif
-
-	/* Freescale E500 core RM section 6.4.1. */
-	msr = msr | PSL_WE;
-	__asm __volatile("msync; mtmsr %0; isync" :: "r" (msr));
-}
-
-int
-cpu_idle_wakeup(int cpu)
-{
-
-	return (0);
-}
-
 void
 spinlock_enter(void)
 {

Modified: user/nwhitehorn/ps3/powerpc/powerpc/cpu.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/cpu.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/powerpc/cpu.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -64,6 +64,7 @@
 #include <sys/conf.h>
 #include <sys/cpu.h>
 #include <sys/kernel.h>
+#include <sys/proc.h>
 #include <sys/sysctl.h>
 
 #include <machine/bus.h>
@@ -73,12 +74,15 @@
 #include <machine/smp.h>
 #include <machine/spr.h>
 
-int powerpc_pow_enabled;
-
 static void	cpu_6xx_setup(int cpuid, uint16_t vers);
 static void	cpu_e500_setup(int cpuid, uint16_t vers);
 static void	cpu_970_setup(int cpuid, uint16_t vers);
 
+int powerpc_pow_enabled;
+void (*cpu_idle_hook)(void) = NULL;
+static void	cpu_idle_60x(void);
+static void	cpu_idle_e500(void);
+
 struct cputab {
 	const char	*name;
 	uint16_t	version;
@@ -377,6 +381,9 @@ cpu_6xx_setup(int cpuid, uint16_t vers)
 	}
 
 	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
+
+	if (cpu_idle_hook == NULL)
+		cpu_idle_hook = cpu_idle_60x;
 }
 
 
@@ -444,6 +451,9 @@ cpu_e500_setup(int cpuid, uint16_t vers)
 	mtspr(SPR_HID0, hid0);
 
 	printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK);
+
+	if (cpu_idle_hook == NULL)
+		cpu_idle_hook = cpu_idle_e500;
 }
 
 static void
@@ -481,6 +491,8 @@ cpu_970_setup(int cpuid, uint16_t vers)
 	    : "=r" (hid0_hi) : "K" (SPR_HID0));
 	printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
 #endif
+
+	cpu_idle_hook = cpu_idle_60x;
 }
 
 static int
@@ -493,3 +505,74 @@ cpu_feature_bit(SYSCTL_HANDLER_ARGS)
 	return (sysctl_handle_int(oidp, &result, 0, req));
 }
 
+void
+cpu_idle(int busy)
+{
+
+#ifdef INVARIANTS
+	if ((mfmsr() & PSL_EE) != PSL_EE) {
+		struct thread *td = curthread;
+		printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
+		panic("ints disabled in idleproc!");
+	}
+#endif
+
+	if (cpu_idle_hook != NULL)
+		cpu_idle_hook();
+}
+
+int
+cpu_idle_wakeup(int cpu)
+{
+	return (0);
+}
+
+static void
+cpu_idle_60x(void)
+{
+	register_t msr;
+	uint16_t vers;
+
+	if (!powerpc_pow_enabled)
+		return;
+
+	msr = mfmsr();
+	vers = mfpvr() >> 16;
+
+#ifdef AIM
+	switch (vers) {
+	case IBM970:
+	case IBM970FX:
+	case IBM970MP:
+	case MPC7447A:
+	case MPC7448:
+	case MPC7450:
+	case MPC7455:
+	case MPC7457:
+		__asm __volatile("\
+			    dssall; sync; mtmsr %0; isync"
+			    :: "r"(msr | PSL_POW));
+		break;
+	default:
+		powerpc_sync();
+		mtmsr(msr | PSL_POW);
+		isync();
+		break;
+	}
+#endif
+}
+
+static void
+cpu_idle_e500(void)
+{
+	register_t msr;
+
+	msr = mfmsr();
+
+#ifdef E500
+	/* Freescale E500 core RM section 6.4.1. */
+	__asm __volatile("msync; mtmsr %0; isync" ::
+	    "r" (msr | PSL_WE));
+#endif
+}
+

Modified: user/nwhitehorn/ps3/powerpc/powerpc/mp_machdep.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/mp_machdep.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/powerpc/mp_machdep.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -100,13 +100,6 @@ machdep_ap_bootstrap(void)
 	sched_throw(NULL);
 }
 
-struct cpu_group *
-cpu_topo(void)
-{
-
-	return (smp_topo_none());
-}
-
 void
 cpu_mp_setmaxid(void)
 {

Modified: user/nwhitehorn/ps3/powerpc/powerpc/platform.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/platform.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/powerpc/platform.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/ktr.h>
 #include <sys/mutex.h>
 #include <sys/systm.h>
+#include <sys/smp.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
 
@@ -111,6 +112,14 @@ platform_smp_start_cpu(struct pcpu *cpu)
 	return (PLATFORM_SMP_START_CPU(plat_obj, cpu));
 }
 
+#ifdef SMP
+struct cpu_group *
+cpu_topo(void)
+{
+        return (PLATFORM_SMP_TOPO(plat_obj));
+}
+#endif
+
 /*
  * Reset back to firmware.
  */

Modified: user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/powerpc/platform_if.m	Thu Sep  2 16:09:46 2010	(r212151)
@@ -30,6 +30,7 @@
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/systm.h>
+#include <sys/smp.h>
 
 #include <machine/platform.h>
 #include <machine/platformvar.h>
@@ -67,6 +68,14 @@ CODE {
 	{
 		return (ENOENT);
 	}
+	static struct cpu_group *platform_null_smp_topo(platform_t plat)
+	{
+#ifdef SMP
+		return (smp_topo_none());
+#else
+		return (NULL);
+#endif
+	}
 	static vm_offset_t platform_null_real_maxaddr(platform_t plat)
 	{
 		return (VM_MAX_ADDRESS);
@@ -176,6 +185,13 @@ METHOD int smp_start_cpu {
 };
 
 /**
+ * @brief Return SMP topology
+ */
+METHOD cpu_group_t smp_topo {
+	platform_t	_plat;
+} DEFAULT platform_null_smp_topo;
+
+/**
  * @brief Reset system
  */
 METHOD void reset {

Modified: user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/ps3/platform_ps3.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -64,11 +64,15 @@ static void ps3_mem_regions(platform_t, 
     struct mem_region **avail, int *availsz);
 static vm_offset_t ps3_real_maxaddr(platform_t);
 static u_long ps3_timebase_freq(platform_t, struct cpuref *cpuref);
+#ifdef SMP
 static int ps3_smp_first_cpu(platform_t, struct cpuref *cpuref);
 static int ps3_smp_next_cpu(platform_t, struct cpuref *cpuref);
 static int ps3_smp_get_bsp(platform_t, struct cpuref *cpuref);
 static int ps3_smp_start_cpu(platform_t, struct pcpu *cpu);
+static struct cpu_group *ps3_smp_topo(platform_t);
+#endif
 static void ps3_reset(platform_t);
+static void ps3_cpu_idle(void);
 
 static platform_method_t ps3_methods[] = {
 	PLATFORMMETHOD(platform_probe, 		ps3_probe),
@@ -77,10 +81,13 @@ static platform_method_t ps3_methods[] =
 	PLATFORMMETHOD(platform_real_maxaddr,	ps3_real_maxaddr),
 	PLATFORMMETHOD(platform_timebase_freq,	ps3_timebase_freq),
 
+#ifdef SMP
 	PLATFORMMETHOD(platform_smp_first_cpu,	ps3_smp_first_cpu),
 	PLATFORMMETHOD(platform_smp_next_cpu,	ps3_smp_next_cpu),
 	PLATFORMMETHOD(platform_smp_get_bsp,	ps3_smp_get_bsp),
 	PLATFORMMETHOD(platform_smp_start_cpu,	ps3_smp_start_cpu),
+	PLATFORMMETHOD(platform_smp_topo,	ps3_smp_topo),
+#endif
 
 	PLATFORMMETHOD(platform_reset,		ps3_reset),
 
@@ -147,6 +154,7 @@ ps3_attach(platform_t plat)
 	    0, 0x04 /* any address */, &avail_regions[1].mr_start, &junk);
 
 	pmap_mmu_install("mmu_ps3", BUS_PROBE_SPECIFIC);
+	cpu_idle_hook = ps3_cpu_idle;
 
 	return (0);
 }
@@ -174,6 +182,7 @@ ps3_timebase_freq(platform_t plat, struc
 	return (ticks);
 }
 
+#ifdef SMP
 static int
 ps3_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
 {
@@ -210,7 +219,6 @@ ps3_smp_get_bsp(platform_t plat, struct 
 static int
 ps3_smp_start_cpu(platform_t plat, struct pcpu *pc)
 {
-#ifdef SMP
 	/* loader(8) is spinning on 0x40 == 0 right now */
 	uint32_t *secondary_spin_sem = (uint32_t *)(0x40);
 	int timeout;
@@ -228,12 +236,15 @@ ps3_smp_start_cpu(platform_t plat, struc
 		DELAY(100);
 
 	return ((pc->pc_awake) ? 0 : EBUSY);
-#else
-	/* No SMP support */
-	return (ENXIO);
-#endif
 }
 
+static struct cpu_group *
+ps3_smp_topo(platform_t plat)
+{
+	return (smp_topo_1level(CG_SHARE_L1, 2, CG_FLAG_SMT));
+}
+#endif
+
 static void
 ps3_reset(platform_t plat)
 {
@@ -246,3 +257,19 @@ ps3_real_maxaddr(platform_t plat)
 	return (avail_regions[0].mr_start + avail_regions[0].mr_size);
 }
 
+static void
+ps3_cpu_idle(void)
+{
+	static volatile int pausing = 0;
+
+	/*
+	 * XXX: It appears that the PS3 can livelock if both threads
+	 * call lv1_pause(0) simultaneously.
+	 */
+	if (!atomic_cmpset_int(&pausing, 0, 1))
+		return;
+
+	lv1_pause(0);
+	pausing = 0;
+}
+

Modified: user/nwhitehorn/ps3/powerpc/ps3/ps3pic.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/ps3pic.c	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/powerpc/ps3/ps3pic.c	Thu Sep  2 16:09:46 2010	(r212151)
@@ -62,6 +62,7 @@ struct ps3pic_softc {
 	uint64_t	*bitmap_thread1;
 	uint64_t	*mask_thread1;
 
+	uint64_t	sc_ipi_outlet[2];
 	int		sc_vector[64];
 };
 
@@ -119,9 +120,6 @@ ps3pic_attach(device_t dev)
 	uint64_t ppe;
 	int thread;
 
-	powerpc_register_pic(dev, 64);
-	root_pic = dev; /* PS3s have only one PIC */
-
 	sc = device_get_softc(dev);
 
 	sc->bitmap_thread0 = contigmalloc(128 /* 512 bits * 2 */, M_PS3PIC,
@@ -138,8 +136,19 @@ ps3pic_attach(device_t dev)
 #ifdef SMP
 	lv1_configure_irq_state_bitmap(ppe, !thread,
 	    vtophys(sc->bitmap_thread1));
+
+	/* Map both IPIs to the same VIRQ to avoid changes in intr_machdep */
+	lv1_construct_event_receive_port(&sc->sc_ipi_outlet[0]);
+	lv1_connect_irq_plug_ext(ppe, thread, sc->sc_ipi_outlet[0],
+	    sc->sc_ipi_outlet[0], 0);
+	lv1_construct_event_receive_port(&sc->sc_ipi_outlet[1]);
+	lv1_connect_irq_plug_ext(ppe, !thread, sc->sc_ipi_outlet[0],
+	    sc->sc_ipi_outlet[1], 0);
 #endif
 
+	powerpc_register_pic(dev, sc->sc_ipi_outlet[0]);
+	root_pic = dev; /* PS3s have only one PIC */
+
 	return (0);
 }
 
@@ -175,9 +184,6 @@ ps3pic_enable(device_t dev, u_int irq, u
 {
 	struct ps3pic_softc *sc;
 
-	if (irq > 63) /* IPI */
-		return;
-
 	sc = device_get_softc(dev);
 	sc->sc_vector[irq] = vector;
 
@@ -197,8 +203,12 @@ ps3pic_eoi(device_t dev, u_int irq)
 }
 
 static void
-ps3pic_ipi(device_t dev, u_int irq)
+ps3pic_ipi(device_t dev, u_int cpu)
 {
+	struct ps3pic_softc *sc;
+	sc = device_get_softc(dev);
+
+	lv1_send_event_locally(sc->sc_ipi_outlet[cpu]);
 }
 
 static void
@@ -208,6 +218,11 @@ ps3pic_mask(device_t dev, u_int irq)
 	uint64_t ppe;
 
 	sc = device_get_softc(dev);
+
+	/* Do not mask IPIs! */
+	if (irq == sc->sc_ipi_outlet[0])
+		return;
+
 	sc->mask_thread0[0] &= ~(1UL << (63 - irq));
 	sc->mask_thread1[0] &= ~(1UL << (63 - irq));
 

Modified: user/nwhitehorn/ps3/sys/smp.h
==============================================================================
--- user/nwhitehorn/ps3/sys/smp.h	Thu Sep  2 16:09:09 2010	(r212150)
+++ user/nwhitehorn/ps3/sys/smp.h	Thu Sep  2 16:09:46 2010	(r212151)
@@ -16,8 +16,6 @@
 
 #ifndef LOCORE
 
-#ifdef SMP
-
 /*
  * Topology of a NUMA or HTT system.
  *
@@ -41,6 +39,8 @@ struct cpu_group {
 	int8_t		cg_flags;	/* Traversal modifiers. */
 };
 
+typedef struct cpu_group *cpu_group_t;
+
 /*
  * Defines common resources for CPUs in the group.  The highest level
  * resource should be used when multiple are shared.
@@ -60,6 +60,7 @@ struct cpu_group {
 /*
  * Convenience routines for building topologies.
  */
+#ifdef SMP
 struct cpu_group *smp_topo(void);
 struct cpu_group *smp_topo_none(void);
 struct cpu_group *smp_topo_1level(int l1share, int l1count, int l1flags);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009021609.o82G9kJ1010454>