Fix timebase hardware sync on SMP PowerMacs (both oldworld dual 604s and

core99 dual G4s).
parent 96f124ee
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <asm/time.h> #include <asm/time.h>
#include <asm/open_pic.h> #include <asm/open_pic.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/keylargo.h>
/* /*
* Powersurge (old powermac SMP) support. * Powersurge (old powermac SMP) support.
...@@ -108,9 +109,16 @@ static volatile u32 *psurge_start; ...@@ -108,9 +109,16 @@ static volatile u32 *psurge_start;
/* what sort of powersurge board we have */ /* what sort of powersurge board we have */
static int psurge_type = PSURGE_NONE; static int psurge_type = PSURGE_NONE;
/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
volatile static long int core99_l2_cache; volatile static long int core99_l2_cache;
volatile static long int core99_l3_cache; volatile static long int core99_l3_cache;
/* Timebase freeze GPIO */
static unsigned int core99_tb_gpio;
/* Sync flag for HW tb sync */
static volatile int sec_tb_reset = 0;
static void __init static void __init
core99_init_caches(int cpu) core99_init_caches(int cpu)
{ {
...@@ -380,7 +388,6 @@ static void __init smp_psurge_kick_cpu(int nr) ...@@ -380,7 +388,6 @@ static void __init smp_psurge_kick_cpu(int nr)
*/ */
static void __init psurge_dual_sync_tb(int cpu_nr) static void __init psurge_dual_sync_tb(int cpu_nr)
{ {
static volatile int sec_tb_reset = 0;
int t; int t;
set_dec(tb_ticks_per_jiffy); set_dec(tb_ticks_per_jiffy);
...@@ -408,8 +415,15 @@ smp_psurge_setup_cpu(int cpu_nr) ...@@ -408,8 +415,15 @@ smp_psurge_setup_cpu(int cpu_nr)
{ {
if (cpu_nr == 0) { if (cpu_nr == 0) {
if (num_online_cpus() < 2) /* If we failed to start the second CPU, we should still
* send it an IPI to start the timebase & DEC or we might
* have them stuck.
*/
if (num_online_cpus() < 2) {
if (psurge_type == PSURGE_DUAL)
psurge_set_ipi(1);
return; return;
}
/* reset the entry point so if we get another intr we won't /* reset the entry point so if we get another intr we won't
* try to startup again */ * try to startup again */
out_be32(psurge_start, 0x100); out_be32(psurge_start, 0x100);
...@@ -421,19 +435,42 @@ smp_psurge_setup_cpu(int cpu_nr) ...@@ -421,19 +435,42 @@ smp_psurge_setup_cpu(int cpu_nr)
psurge_dual_sync_tb(cpu_nr); psurge_dual_sync_tb(cpu_nr);
} }
void __init
smp_psurge_take_timebase(void)
{
/* Dummy implementation */
}
void __init
smp_psurge_give_timebase(void)
{
/* Dummy implementation */
}
static int __init static int __init
smp_core99_probe(void) smp_core99_probe(void)
{ {
extern int powersave_nap;
struct device_node *cpus; struct device_node *cpus;
int i, ncpus = 1; int i, ncpus = 1;
extern int powersave_nap; u32 *tbprop;
if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
cpus = find_type_devices("cpu"); cpus = find_type_devices("cpu");
if (cpus) if (cpus == NULL)
while ((cpus = cpus->next) != NULL) return 0;
++ncpus;
tbprop = (u32 *)get_property(cpus, "timebase-enable", NULL);
if (tbprop)
core99_tb_gpio = *tbprop;
else
core99_tb_gpio = KL_GPIO_TB_ENABLE;
while ((cpus = cpus->next) != NULL)
++ncpus;
printk("smp_core99_probe: found %d cpus\n", ncpus); printk("smp_core99_probe: found %d cpus\n", ncpus);
if (ncpus > 1) { if (ncpus > 1) {
openpic_request_IPIs(); openpic_request_IPIs();
for (i = 1; i < ncpus; ++i) for (i = 1; i < ncpus; ++i)
...@@ -517,14 +554,59 @@ smp_core99_setup_cpu(int cpu_nr) ...@@ -517,14 +554,59 @@ smp_core99_setup_cpu(int cpu_nr)
if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
} }
void __init
smp_core99_take_timebase(void)
{
/* Secondary processor "takes" the timebase by freezing
* it, resetting its local TB and telling CPU 0 to go on
*/
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
mb();
set_dec(tb_ticks_per_jiffy);
set_tb(0, 0);
last_jiffy_stamp(smp_processor_id()) = 0;
mb();
sec_tb_reset = 1;
}
void __init
smp_core99_give_timebase(void)
{
unsigned int t;
/* Primary processor waits for secondary to have frozen
* the timebase, resets local TB, and kick timebase again
*/
/* wait for the secondary to have reset its TB before proceeding */
for (t = 1000; t > 0 && !sec_tb_reset; --t)
udelay(1000);
if (t == 0)
printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
set_dec(tb_ticks_per_jiffy);
set_tb(0, 0);
last_jiffy_stamp(smp_processor_id()) = 0;
mb();
/* Now, restart the timebase by leaving the GPIO to an open collector */
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
smp_tb_synchronized = 1;
}
/* PowerSurge-style Macs */ /* PowerSurge-style Macs */
struct smp_ops_t psurge_smp_ops __pmacdata = { struct smp_ops_t psurge_smp_ops __pmacdata = {
.message_pass = smp_psurge_message_pass, .message_pass = smp_psurge_message_pass,
.probe = smp_psurge_probe, .probe = smp_psurge_probe,
.kick_cpu = smp_psurge_kick_cpu, .kick_cpu = smp_psurge_kick_cpu,
.setup_cpu = smp_psurge_setup_cpu, .setup_cpu = smp_psurge_setup_cpu,
.give_timebase = smp_generic_give_timebase, .give_timebase = smp_psurge_give_timebase,
.take_timebase = smp_generic_take_timebase, .take_timebase = smp_psurge_take_timebase,
}; };
/* Core99 Macs (dual G4s) */ /* Core99 Macs (dual G4s) */
...@@ -533,6 +615,6 @@ struct smp_ops_t core99_smp_ops __pmacdata = { ...@@ -533,6 +615,6 @@ struct smp_ops_t core99_smp_ops __pmacdata = {
.probe = smp_core99_probe, .probe = smp_core99_probe,
.kick_cpu = smp_core99_kick_cpu, .kick_cpu = smp_core99_kick_cpu,
.setup_cpu = smp_core99_setup_cpu, .setup_cpu = smp_core99_setup_cpu,
.give_timebase = smp_generic_give_timebase, .give_timebase = smp_core99_give_timebase,
.take_timebase = smp_generic_take_timebase, .take_timebase = smp_core99_take_timebase,
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment