diff options
Diffstat (limited to 'arch/ppc')
-rw-r--r-- | arch/ppc/platforms/pmac_smp.c | 78 |
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 */ |
118 | static volatile int sec_tb_reset = 0; | 118 | static volatile int sec_tb_reset = 0; |
119 | static unsigned int pri_tb_hi, pri_tb_lo; | ||
120 | static unsigned int pri_tb_stamp; | ||
119 | 121 | ||
120 | static void __init core99_init_caches(int cpu) | 122 | static 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 | ||
579 | void __init smp_core99_take_timebase(void) | 581 | /* not __init, called in sleep/wakeup code */ |
582 | void 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 | ||
596 | void __init smp_core99_give_timebase(void) | 607 | /* not __init, called in sleep/wakeup code */ |
608 | void 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 | ||