Changeset View
Standalone View
sys/powerpc/powermac/platform_powermac.c
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
#include <machine/platformvar.h> | #include <machine/platformvar.h> | ||||
#include <machine/setjmp.h> | #include <machine/setjmp.h> | ||||
#include <machine/smp.h> | #include <machine/smp.h> | ||||
#include <machine/spr.h> | #include <machine/spr.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include <machine/ofw_machdep.h> | #include <machine/ofw_machdep.h> | ||||
#include <powerpc/powermac/platform_powermac.h> | |||||
#include "platform_if.h" | #include "platform_if.h" | ||||
extern void *ap_pcpu; | extern volatile void *ap_pcpu; | ||||
static void dummy_timebase(device_t, bool); | |||||
static device_t powermac_tb_dev; | |||||
static void (*freeze_timebase)(device_t, bool) = dummy_timebase; | |||||
static int powermac_probe(platform_t); | static int powermac_probe(platform_t); | ||||
static int powermac_attach(platform_t); | static int powermac_attach(platform_t); | ||||
void powermac_mem_regions(platform_t, struct mem_region *phys, int *physsz, | void powermac_mem_regions(platform_t, struct mem_region *phys, int *physsz, | ||||
struct mem_region *avail, int *availsz); | struct mem_region *avail, int *availsz); | ||||
static u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref); | static u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref); | ||||
static int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref); | static int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref); | ||||
static int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref); | static int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref); | ||||
static int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref); | static int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref); | ||||
▲ Show 20 Lines • Show All 322 Lines • ▼ Show 20 Lines | #ifdef SMP | ||||
return ((pc->pc_awake) ? 0 : EBUSY); | return ((pc->pc_awake) ? 0 : EBUSY); | ||||
#else | #else | ||||
/* No SMP support */ | /* No SMP support */ | ||||
return (ENXIO); | return (ENXIO); | ||||
#endif | #endif | ||||
} | } | ||||
void | |||||
powermac_register_timebase(device_t dev, powermac_tb_disable_t cb) | |||||
{ | |||||
powermac_tb_dev = dev; | |||||
freeze_timebase = cb; | |||||
} | |||||
static void | static void | ||||
powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap) | powermac_smp_timebase_sync(platform_t plat, u_long tb, int ap) | ||||
{ | { | ||||
static volatile bool tb_ready; | |||||
static volatile int cpu_done; | |||||
/* | |||||
* XXX Temporary fallback for platforms we don't know how to freeze. | |||||
* | |||||
* This needs to be replaced with a cpu-to-cpu software sync | |||||
* protocol, because this is not a consistent way to sync timebase. | |||||
*/ | |||||
mttb(tb); | mttb(tb); | ||||
if (freeze_timebase == dummy_timebase) | |||||
return; | |||||
if (ap) { | |||||
/* APs. Hold off until we get a stable timebase. */ | |||||
critical_enter(); | |||||
while (!tb_ready) | |||||
atomic_thread_fence_seq_cst(); | |||||
mttb(tb); | |||||
atomic_add_int(&cpu_done, 1); | |||||
while (cpu_done < mp_ncpus) | |||||
atomic_thread_fence_seq_cst(); | |||||
markmi_dsl-only.net: I still do not see how the code that involves:
```
void cpu_sleep()… | |||||
Done Inline ActionsYeah, I'm aware. cpu_sleep() is misnamed and is only used on PMU machines, which are never SMP according to jhibbits. And the cpudep_ap_setup() one I am planning on just changing to mttb(0);. It's tied to suspend/resume support, which is not possible to support in SMP currently (the code has some low level assumptions with static variables that totally fall apart under SMP, and attempting to suspend/resume on SMP will screw up the pcpu data, etc. We would have to implement a lookup table to map the pcpu data to cores after resume.) bdragon: Yeah, I'm aware.
cpu_sleep() is misnamed and is only used on PMU machines, which are never SMP… | |||||
Not Done Inline ActionsI looked up some old notes. According to them cpudep_ap_setup happens during cpu_reset_handler So it would appear that before testing this code, the markmi_dsl-only.net: I looked up some old notes. According to them
(summarized):
cpudep_ap_setup happens during… | |||||
Not Done Inline ActionsIn case it is unclear: sys/powerpc/aim/aim_machdep.c: platform_smp_timebase_sync(timebase, 0); sys/powerpc/aim/mp_cpudep.c: platform_smp_timebase_sync(0, 1); So the usage in question is AIM specific. markmi_dsl-only.net: In case it is unclear:
```
sys/powerpc/aim/aim_machdep.c: platform_smp_timebase_sync(timebase… | |||||
critical_exit(); | |||||
} else { | |||||
/* BSP */ | |||||
critical_enter(); | |||||
/* Ensure cpu_done is zeroed so we can resync at runtime */ | |||||
atomic_set_int(&cpu_done, 0); | |||||
freeze_timebase(powermac_tb_dev, true); | |||||
tb_ready = true; | |||||
mttb(tb); | |||||
atomic_add_int(&cpu_done, 1); | |||||
while (cpu_done < mp_ncpus) | |||||
atomic_thread_fence_seq_cst(); | |||||
freeze_timebase(powermac_tb_dev, false); | |||||
/* Reset tb_ready so we can resync at runtime */ | |||||
tb_ready = false; | |||||
critical_exit(); | |||||
} | |||||
} | |||||
/* Fallback freeze. In case no real handler is found in the device tree. */ | |||||
static void | |||||
dummy_timebase(device_t dev, bool freeze) | |||||
{ | |||||
/* Nothing to do here, move along. */ | |||||
} | } | ||||
static void | static void | ||||
powermac_reset(platform_t platform) | powermac_reset(platform_t platform) | ||||
{ | { | ||||
OF_reboot(); | OF_reboot(); | ||||
} | } | ||||
Show All 14 Lines |
I still do not see how the code that involves:
is supposed to work with these sort of cpu_done vs. mp_ncpus loops.
(The two ap_timebase uses of platform_smp_timebase_sync make sense to
me, at least as of when I last looked at the details, including cpu_done starting
with an appropriate value.)