From b87d008719fd394b94d0cb4ef93abfed61defc2c Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 11 Oct 2003 20:14:01 +0200 Subject: [PATCH] Fix timebase hardware sync on SMP PowerMacs (both oldworld dual 604s and core99 dual G4s). --- arch/ppc/platforms/pmac_smp.c | 102 ++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c index 390b447218d57..d230b9890a05e 100644 --- a/arch/ppc/platforms/pmac_smp.c +++ b/arch/ppc/platforms/pmac_smp.c @@ -51,6 +51,7 @@ #include #include #include +#include /* * Powersurge (old powermac SMP) support. @@ -108,9 +109,16 @@ static volatile u32 *psurge_start; /* what sort of powersurge board we have */ 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_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 core99_init_caches(int cpu) { @@ -380,7 +388,6 @@ static void __init smp_psurge_kick_cpu(int nr) */ static void __init psurge_dual_sync_tb(int cpu_nr) { - static volatile int sec_tb_reset = 0; int t; set_dec(tb_ticks_per_jiffy); @@ -408,8 +415,15 @@ smp_psurge_setup_cpu(int cpu_nr) { 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; + } /* reset the entry point so if we get another intr we won't * try to startup again */ out_be32(psurge_start, 0x100); @@ -421,19 +435,42 @@ smp_psurge_setup_cpu(int 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 smp_core99_probe(void) { + extern int powersave_nap; struct device_node *cpus; int i, ncpus = 1; - extern int powersave_nap; + u32 *tbprop; if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); cpus = find_type_devices("cpu"); - if (cpus) - while ((cpus = cpus->next) != NULL) - ++ncpus; + if (cpus == NULL) + return 0; + + 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); + if (ncpus > 1) { openpic_request_IPIs(); for (i = 1; i < ncpus; ++i) @@ -517,14 +554,59 @@ smp_core99_setup_cpu(int cpu_nr) 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 */ struct smp_ops_t psurge_smp_ops __pmacdata = { .message_pass = smp_psurge_message_pass, .probe = smp_psurge_probe, .kick_cpu = smp_psurge_kick_cpu, .setup_cpu = smp_psurge_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, + .give_timebase = smp_psurge_give_timebase, + .take_timebase = smp_psurge_take_timebase, }; /* Core99 Macs (dual G4s) */ @@ -533,6 +615,6 @@ struct smp_ops_t core99_smp_ops __pmacdata = { .probe = smp_core99_probe, .kick_cpu = smp_core99_kick_cpu, .setup_cpu = smp_core99_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, + .give_timebase = smp_core99_give_timebase, + .take_timebase = smp_core99_take_timebase, }; -- 2.53.0