aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-04-16 18:24:16 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:24:16 -0400
commit6460b4cceba0181308042c8d8794eb679bfa22e5 (patch)
treea0b9f388bf205b7f0fff9f5c7f8e31dacf12be7e
parent35b535d9cc8dce79c3b72f47c4417c3159d7a8c9 (diff)
[PATCH] ppc32: improve timebase sync for SMP
Currently the procedure in the ppc32 kernel that synchronizes the timebase registers across an SMP powermac system does so by setting both timebases to zero. That is OK at boot but causes problems if done later. So that we can do hotplug CPU on these machines, this patch changes the code so it reads the timebase from one CPU and transfers the value to the other CPU. (Hotplug CPU is needed for sleep (aka suspend to RAM) to work.) Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ppc/platforms/pmac_smp.c78
1 files changed, 54 insertions, 24 deletions
diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
index 2b88745576a0..731841f9a5b8 100644
--- a/arch/ppc/platforms/pmac_smp.c
+++ b/arch/ppc/platforms/pmac_smp.c
@@ -116,6 +116,8 @@ static unsigned int core99_tb_gpio;
116 116
117/* Sync flag for HW tb sync */ 117/* Sync flag for HW tb sync */
118static volatile int sec_tb_reset = 0; 118static volatile int sec_tb_reset = 0;
119static unsigned int pri_tb_hi, pri_tb_lo;
120static unsigned int pri_tb_stamp;
119 121
120static void __init core99_init_caches(int cpu) 122static void __init core99_init_caches(int cpu)
121{ 123{
@@ -453,7 +455,7 @@ static int __init smp_core99_probe(void)
453#endif 455#endif
454 struct device_node *cpus, *firstcpu; 456 struct device_node *cpus, *firstcpu;
455 int i, ncpus = 0, boot_cpu = -1; 457 int i, ncpus = 0, boot_cpu = -1;
456 u32 *tbprop; 458 u32 *tbprop = NULL;
457 459
458 if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345); 460 if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
459 cpus = firstcpu = find_type_devices("cpu"); 461 cpus = firstcpu = find_type_devices("cpu");
@@ -576,46 +578,74 @@ static void __init smp_core99_setup_cpu(int cpu_nr)
576 } 578 }
577} 579}
578 580
579void __init smp_core99_take_timebase(void) 581/* not __init, called in sleep/wakeup code */
582void smp_core99_take_timebase(void)
580{ 583{
581 /* Secondary processor "takes" the timebase by freezing 584 unsigned long flags;
582 * it, resetting its local TB and telling CPU 0 to go on 585
583 */ 586 /* tell the primary we're here */
584 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); 587 sec_tb_reset = 1;
585 pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
586 mb(); 588 mb();
587 589
588 set_dec(tb_ticks_per_jiffy); 590 /* wait for the primary to set pri_tb_hi/lo */
589 set_tb(0, 0); 591 while (sec_tb_reset < 2)
590 last_jiffy_stamp(smp_processor_id()) = 0; 592 mb();
591 593
594 /* set our stuff the same as the primary */
595 local_irq_save(flags);
596 set_dec(1);
597 set_tb(pri_tb_hi, pri_tb_lo);
598 last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
599 mb();
600
601 /* tell the primary we're done */
602 sec_tb_reset = 0;
592 mb(); 603 mb();
593 sec_tb_reset = 1; 604 local_irq_restore(flags);
594} 605}
595 606
596void __init smp_core99_give_timebase(void) 607/* not __init, called in sleep/wakeup code */
608void smp_core99_give_timebase(void)
597{ 609{
610 unsigned long flags;
598 unsigned int t; 611 unsigned int t;
599 612
600 /* Primary processor waits for secondary to have frozen 613 /* wait for the secondary to be in take_timebase */
601 * the timebase, resets local TB, and kick timebase again 614 for (t = 100000; t > 0 && !sec_tb_reset; --t)
602 */ 615 udelay(10);
603 /* wait for the secondary to have reset its TB before proceeding */ 616 if (!sec_tb_reset) {
604 for (t = 1000; t > 0 && !sec_tb_reset; --t)
605 udelay(1000);
606 if (t == 0)
607 printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); 617 printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
618 return;
619 }
608 620
609 set_dec(tb_ticks_per_jiffy); 621 /* freeze the timebase and read it */
610 set_tb(0, 0); 622 /* disable interrupts so the timebase is disabled for the
611 last_jiffy_stamp(smp_processor_id()) = 0; 623 shortest possible time */
624 local_irq_save(flags);
625 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
626 pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
627 mb();
628 pri_tb_hi = get_tbu();
629 pri_tb_lo = get_tbl();
630 pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
612 mb(); 631 mb();
613 632
633 /* tell the secondary we're ready */
634 sec_tb_reset = 2;
635 mb();
636
637 /* wait for the secondary to have taken it */
638 for (t = 100000; t > 0 && sec_tb_reset; --t)
639 udelay(10);
640 if (sec_tb_reset)
641 printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
642 else
643 smp_tb_synchronized = 1;
644
614 /* Now, restart the timebase by leaving the GPIO to an open collector */ 645 /* Now, restart the timebase by leaving the GPIO to an open collector */
615 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); 646 pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
616 pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); 647 pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
617 648 local_irq_restore(flags);
618 smp_tb_synchronized = 1;
619} 649}
620 650
621 651