diff options
Diffstat (limited to 'arch/powerpc/platforms/powermac/smp.c')
-rw-r--r-- | arch/powerpc/platforms/powermac/smp.c | 319 |
1 files changed, 168 insertions, 151 deletions
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index 862f1e985c19..df01bb8feb16 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -361,7 +361,6 @@ static void __init psurge_dual_sync_tb(int cpu_nr) | |||
361 | set_dec(tb_ticks_per_jiffy); | 361 | set_dec(tb_ticks_per_jiffy); |
362 | /* XXX fixme */ | 362 | /* XXX fixme */ |
363 | set_tb(0, 0); | 363 | set_tb(0, 0); |
364 | last_jiffy_stamp(cpu_nr) = 0; | ||
365 | 364 | ||
366 | if (cpu_nr > 0) { | 365 | if (cpu_nr > 0) { |
367 | mb(); | 366 | mb(); |
@@ -429,15 +428,62 @@ struct smp_ops_t psurge_smp_ops = { | |||
429 | }; | 428 | }; |
430 | #endif /* CONFIG_PPC32 - actually powersurge support */ | 429 | #endif /* CONFIG_PPC32 - actually powersurge support */ |
431 | 430 | ||
431 | /* | ||
432 | * Core 99 and later support | ||
433 | */ | ||
434 | |||
435 | static void (*pmac_tb_freeze)(int freeze); | ||
436 | static unsigned long timebase; | ||
437 | static int tb_req; | ||
438 | |||
439 | static void smp_core99_give_timebase(void) | ||
440 | { | ||
441 | unsigned long flags; | ||
442 | |||
443 | local_irq_save(flags); | ||
444 | |||
445 | while(!tb_req) | ||
446 | barrier(); | ||
447 | tb_req = 0; | ||
448 | (*pmac_tb_freeze)(1); | ||
449 | mb(); | ||
450 | timebase = get_tb(); | ||
451 | mb(); | ||
452 | while (timebase) | ||
453 | barrier(); | ||
454 | mb(); | ||
455 | (*pmac_tb_freeze)(0); | ||
456 | mb(); | ||
457 | |||
458 | local_irq_restore(flags); | ||
459 | } | ||
460 | |||
461 | |||
462 | static void __devinit smp_core99_take_timebase(void) | ||
463 | { | ||
464 | unsigned long flags; | ||
465 | |||
466 | local_irq_save(flags); | ||
467 | |||
468 | tb_req = 1; | ||
469 | mb(); | ||
470 | while (!timebase) | ||
471 | barrier(); | ||
472 | mb(); | ||
473 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
474 | timebase = 0; | ||
475 | mb(); | ||
476 | set_dec(tb_ticks_per_jiffy/2); | ||
477 | |||
478 | local_irq_restore(flags); | ||
479 | } | ||
480 | |||
432 | #ifdef CONFIG_PPC64 | 481 | #ifdef CONFIG_PPC64 |
433 | /* | 482 | /* |
434 | * G5s enable/disable the timebase via an i2c-connected clock chip. | 483 | * G5s enable/disable the timebase via an i2c-connected clock chip. |
435 | */ | 484 | */ |
436 | static struct device_node *pmac_tb_clock_chip_host; | 485 | static struct device_node *pmac_tb_clock_chip_host; |
437 | static u8 pmac_tb_pulsar_addr; | 486 | static u8 pmac_tb_pulsar_addr; |
438 | static void (*pmac_tb_freeze)(int freeze); | ||
439 | static DEFINE_SPINLOCK(timebase_lock); | ||
440 | static unsigned long timebase; | ||
441 | 487 | ||
442 | static void smp_core99_cypress_tb_freeze(int freeze) | 488 | static void smp_core99_cypress_tb_freeze(int freeze) |
443 | { | 489 | { |
@@ -447,7 +493,8 @@ static void smp_core99_cypress_tb_freeze(int freeze) | |||
447 | /* Strangely, the device-tree says address is 0xd2, but darwin | 493 | /* Strangely, the device-tree says address is 0xd2, but darwin |
448 | * accesses 0xd0 ... | 494 | * accesses 0xd0 ... |
449 | */ | 495 | */ |
450 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | 496 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, |
497 | pmac_low_i2c_mode_combined); | ||
451 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | 498 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
452 | 0xd0 | pmac_low_i2c_read, | 499 | 0xd0 | pmac_low_i2c_read, |
453 | 0x81, &data, 1); | 500 | 0x81, &data, 1); |
@@ -475,7 +522,8 @@ static void smp_core99_pulsar_tb_freeze(int freeze) | |||
475 | u8 data; | 522 | u8 data; |
476 | int rc; | 523 | int rc; |
477 | 524 | ||
478 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | 525 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, |
526 | pmac_low_i2c_mode_combined); | ||
479 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | 527 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
480 | pmac_tb_pulsar_addr | pmac_low_i2c_read, | 528 | pmac_tb_pulsar_addr | pmac_low_i2c_read, |
481 | 0x2e, &data, 1); | 529 | 0x2e, &data, 1); |
@@ -496,54 +544,14 @@ static void smp_core99_pulsar_tb_freeze(int freeze) | |||
496 | } | 544 | } |
497 | } | 545 | } |
498 | 546 | ||
499 | 547 | static void __init smp_core99_setup_i2c_hwsync(int ncpus) | |
500 | static void smp_core99_give_timebase(void) | ||
501 | { | ||
502 | /* Open i2c bus for synchronous access */ | ||
503 | if (pmac_low_i2c_open(pmac_tb_clock_chip_host, 0)) | ||
504 | panic("Can't open i2c for TB sync !\n"); | ||
505 | |||
506 | spin_lock(&timebase_lock); | ||
507 | (*pmac_tb_freeze)(1); | ||
508 | mb(); | ||
509 | timebase = get_tb(); | ||
510 | spin_unlock(&timebase_lock); | ||
511 | |||
512 | while (timebase) | ||
513 | barrier(); | ||
514 | |||
515 | spin_lock(&timebase_lock); | ||
516 | (*pmac_tb_freeze)(0); | ||
517 | spin_unlock(&timebase_lock); | ||
518 | |||
519 | /* Close i2c bus */ | ||
520 | pmac_low_i2c_close(pmac_tb_clock_chip_host); | ||
521 | } | ||
522 | |||
523 | |||
524 | static void __devinit smp_core99_take_timebase(void) | ||
525 | { | ||
526 | while (!timebase) | ||
527 | barrier(); | ||
528 | spin_lock(&timebase_lock); | ||
529 | set_tb(timebase >> 32, timebase & 0xffffffff); | ||
530 | timebase = 0; | ||
531 | spin_unlock(&timebase_lock); | ||
532 | } | ||
533 | |||
534 | static void __init smp_core99_setup(int ncpus) | ||
535 | { | 548 | { |
536 | struct device_node *cc = NULL; | 549 | struct device_node *cc = NULL; |
537 | struct device_node *p; | 550 | struct device_node *p; |
551 | const char *name = NULL; | ||
538 | u32 *reg; | 552 | u32 *reg; |
539 | int ok; | 553 | int ok; |
540 | 554 | ||
541 | /* HW sync only on these platforms */ | ||
542 | if (!machine_is_compatible("PowerMac7,2") && | ||
543 | !machine_is_compatible("PowerMac7,3") && | ||
544 | !machine_is_compatible("RackMac3,1")) | ||
545 | return; | ||
546 | |||
547 | /* Look for the clock chip */ | 555 | /* Look for the clock chip */ |
548 | while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { | 556 | while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) { |
549 | p = of_get_parent(cc); | 557 | p = of_get_parent(cc); |
@@ -561,114 +569,64 @@ static void __init smp_core99_setup(int ncpus) | |||
561 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { | 569 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { |
562 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | 570 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
563 | pmac_tb_pulsar_addr = 0xd2; | 571 | pmac_tb_pulsar_addr = 0xd2; |
564 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | 572 | name = "Pulsar"; |
565 | } else if (device_is_compatible(cc, "cy28508")) { | 573 | } else if (device_is_compatible(cc, "cy28508")) { |
566 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; | 574 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; |
567 | printk(KERN_INFO "Timebase clock is Cypress chip\n"); | 575 | name = "Cypress"; |
568 | } | 576 | } |
569 | break; | 577 | break; |
570 | case 0xd4: | 578 | case 0xd4: |
571 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | 579 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
572 | pmac_tb_pulsar_addr = 0xd4; | 580 | pmac_tb_pulsar_addr = 0xd4; |
573 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | 581 | name = "Pulsar"; |
574 | break; | 582 | break; |
575 | } | 583 | } |
576 | if (pmac_tb_freeze != NULL) { | 584 | if (pmac_tb_freeze != NULL) |
577 | pmac_tb_clock_chip_host = of_get_parent(cc); | ||
578 | of_node_put(cc); | ||
579 | break; | 585 | break; |
580 | } | ||
581 | } | 586 | } |
582 | if (pmac_tb_freeze == NULL) { | 587 | if (pmac_tb_freeze != NULL) { |
583 | smp_ops->give_timebase = smp_generic_give_timebase; | 588 | struct device_node *p = of_get_parent(cc); |
584 | smp_ops->take_timebase = smp_generic_take_timebase; | 589 | of_node_put(cc); |
590 | while(p && strcmp(p->type, "i2c")) { | ||
591 | cc = of_get_parent(p); | ||
592 | of_node_put(p); | ||
593 | p = cc; | ||
594 | } | ||
595 | if (p == NULL) | ||
596 | goto no_i2c_sync; | ||
597 | /* Open i2c bus for synchronous access */ | ||
598 | if (pmac_low_i2c_open(p, 0)) { | ||
599 | printk(KERN_ERR "Failed top open i2c bus %s for clock" | ||
600 | " sync, fallback to software sync !\n", | ||
601 | p->full_name); | ||
602 | of_node_put(p); | ||
603 | goto no_i2c_sync; | ||
604 | } | ||
605 | pmac_tb_clock_chip_host = p; | ||
606 | printk(KERN_INFO "Processor timebase sync using %s i2c clock\n", | ||
607 | name); | ||
608 | return; | ||
585 | } | 609 | } |
610 | no_i2c_sync: | ||
611 | pmac_tb_freeze = NULL; | ||
586 | } | 612 | } |
587 | 613 | ||
588 | /* nothing to do here, caches are already set up by service processor */ | 614 | #endif /* CONFIG_PPC64 */ |
589 | static inline void __devinit core99_init_caches(int cpu) | ||
590 | { | ||
591 | } | ||
592 | 615 | ||
593 | #else /* CONFIG_PPC64 */ | ||
594 | 616 | ||
595 | /* | 617 | /* |
596 | * SMP G4 powermacs use a GPIO to enable/disable the timebase. | 618 | * SMP G4 and newer G5 use a GPIO to enable/disable the timebase. |
597 | */ | 619 | */ |
598 | 620 | ||
599 | static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ | 621 | static unsigned int core99_tb_gpio; /* Timebase freeze GPIO */ |
600 | 622 | ||
601 | static unsigned int pri_tb_hi, pri_tb_lo; | 623 | static void smp_core99_gpio_tb_freeze(int freeze) |
602 | static unsigned int pri_tb_stamp; | ||
603 | |||
604 | /* not __init, called in sleep/wakeup code */ | ||
605 | void smp_core99_give_timebase(void) | ||
606 | { | 624 | { |
607 | unsigned long flags; | 625 | if (freeze) |
608 | unsigned int t; | 626 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); |
609 | 627 | else | |
610 | /* wait for the secondary to be in take_timebase */ | 628 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); |
611 | for (t = 100000; t > 0 && !sec_tb_reset; --t) | ||
612 | udelay(10); | ||
613 | if (!sec_tb_reset) { | ||
614 | printk(KERN_WARNING "Timeout waiting sync on second CPU\n"); | ||
615 | return; | ||
616 | } | ||
617 | |||
618 | /* freeze the timebase and read it */ | ||
619 | /* disable interrupts so the timebase is disabled for the | ||
620 | shortest possible time */ | ||
621 | local_irq_save(flags); | ||
622 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4); | ||
623 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); | 629 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); |
624 | mb(); | ||
625 | pri_tb_hi = get_tbu(); | ||
626 | pri_tb_lo = get_tbl(); | ||
627 | pri_tb_stamp = last_jiffy_stamp(smp_processor_id()); | ||
628 | mb(); | ||
629 | |||
630 | /* tell the secondary we're ready */ | ||
631 | sec_tb_reset = 2; | ||
632 | mb(); | ||
633 | |||
634 | /* wait for the secondary to have taken it */ | ||
635 | /* note: can't use udelay here, since it needs the timebase running */ | ||
636 | for (t = 10000000; t > 0 && sec_tb_reset; --t) | ||
637 | barrier(); | ||
638 | if (sec_tb_reset) | ||
639 | /* XXX BUG_ON here? */ | ||
640 | printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n"); | ||
641 | |||
642 | /* Now, restart the timebase by leaving the GPIO to an open collector */ | ||
643 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0); | ||
644 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0); | ||
645 | local_irq_restore(flags); | ||
646 | } | ||
647 | |||
648 | /* not __init, called in sleep/wakeup code */ | ||
649 | void smp_core99_take_timebase(void) | ||
650 | { | ||
651 | unsigned long flags; | ||
652 | |||
653 | /* tell the primary we're here */ | ||
654 | sec_tb_reset = 1; | ||
655 | mb(); | ||
656 | |||
657 | /* wait for the primary to set pri_tb_hi/lo */ | ||
658 | while (sec_tb_reset < 2) | ||
659 | mb(); | ||
660 | |||
661 | /* set our stuff the same as the primary */ | ||
662 | local_irq_save(flags); | ||
663 | set_dec(1); | ||
664 | set_tb(pri_tb_hi, pri_tb_lo); | ||
665 | last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp; | ||
666 | mb(); | ||
667 | |||
668 | /* tell the primary we're done */ | ||
669 | sec_tb_reset = 0; | ||
670 | mb(); | ||
671 | local_irq_restore(flags); | ||
672 | } | 630 | } |
673 | 631 | ||
674 | /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ | 632 | /* L2 and L3 cache settings to pass from CPU0 to CPU1 on G4 cpus */ |
@@ -677,6 +635,7 @@ volatile static long int core99_l3_cache; | |||
677 | 635 | ||
678 | static void __devinit core99_init_caches(int cpu) | 636 | static void __devinit core99_init_caches(int cpu) |
679 | { | 637 | { |
638 | #ifndef CONFIG_PPC64 | ||
680 | if (!cpu_has_feature(CPU_FTR_L2CR)) | 639 | if (!cpu_has_feature(CPU_FTR_L2CR)) |
681 | return; | 640 | return; |
682 | 641 | ||
@@ -702,30 +661,80 @@ static void __devinit core99_init_caches(int cpu) | |||
702 | _set_L3CR(core99_l3_cache); | 661 | _set_L3CR(core99_l3_cache); |
703 | printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); | 662 | printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache); |
704 | } | 663 | } |
664 | #endif /* !CONFIG_PPC64 */ | ||
705 | } | 665 | } |
706 | 666 | ||
707 | static void __init smp_core99_setup(int ncpus) | 667 | static void __init smp_core99_setup(int ncpus) |
708 | { | 668 | { |
709 | struct device_node *cpu; | 669 | #ifdef CONFIG_PPC64 |
710 | u32 *tbprop = NULL; | ||
711 | int i; | ||
712 | 670 | ||
713 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ | 671 | /* i2c based HW sync on some G5s */ |
714 | cpu = of_find_node_by_type(NULL, "cpu"); | 672 | if (machine_is_compatible("PowerMac7,2") || |
715 | if (cpu != NULL) { | 673 | machine_is_compatible("PowerMac7,3") || |
716 | tbprop = (u32 *)get_property(cpu, "timebase-enable", NULL); | 674 | machine_is_compatible("RackMac3,1")) |
717 | if (tbprop) | 675 | smp_core99_setup_i2c_hwsync(ncpus); |
718 | core99_tb_gpio = *tbprop; | 676 | |
719 | of_node_put(cpu); | 677 | /* GPIO based HW sync on recent G5s */ |
678 | if (pmac_tb_freeze == NULL) { | ||
679 | struct device_node *np = | ||
680 | of_find_node_by_name(NULL, "timebase-enable"); | ||
681 | u32 *reg = (u32 *)get_property(np, "reg", NULL); | ||
682 | |||
683 | if (np && reg && !strcmp(np->type, "gpio")) { | ||
684 | core99_tb_gpio = *reg; | ||
685 | if (core99_tb_gpio < 0x50) | ||
686 | core99_tb_gpio += 0x50; | ||
687 | pmac_tb_freeze = smp_core99_gpio_tb_freeze; | ||
688 | printk(KERN_INFO "Processor timebase sync using" | ||
689 | " GPIO 0x%02x\n", core99_tb_gpio); | ||
690 | } | ||
720 | } | 691 | } |
721 | 692 | ||
722 | /* XXX should get this from reg properties */ | 693 | #else /* CONFIG_PPC64 */ |
723 | for (i = 1; i < ncpus; ++i) | 694 | |
724 | smp_hw_index[i] = i; | 695 | /* GPIO based HW sync on ppc32 Core99 */ |
725 | powersave_nap = 0; | 696 | if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) { |
726 | } | 697 | struct device_node *cpu; |
698 | u32 *tbprop = NULL; | ||
699 | |||
700 | core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */ | ||
701 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
702 | if (cpu != NULL) { | ||
703 | tbprop = (u32 *)get_property(cpu, "timebase-enable", | ||
704 | NULL); | ||
705 | if (tbprop) | ||
706 | core99_tb_gpio = *tbprop; | ||
707 | of_node_put(cpu); | ||
708 | } | ||
709 | pmac_tb_freeze = smp_core99_gpio_tb_freeze; | ||
710 | printk(KERN_INFO "Processor timebase sync using" | ||
711 | " GPIO 0x%02x\n", core99_tb_gpio); | ||
712 | } | ||
713 | |||
714 | #endif /* CONFIG_PPC64 */ | ||
715 | |||
716 | /* No timebase sync, fallback to software */ | ||
717 | if (pmac_tb_freeze == NULL) { | ||
718 | smp_ops->give_timebase = smp_generic_give_timebase; | ||
719 | smp_ops->take_timebase = smp_generic_take_timebase; | ||
720 | printk(KERN_INFO "Processor timebase sync using software\n"); | ||
721 | } | ||
722 | |||
723 | #ifndef CONFIG_PPC64 | ||
724 | { | ||
725 | int i; | ||
726 | |||
727 | /* XXX should get this from reg properties */ | ||
728 | for (i = 1; i < ncpus; ++i) | ||
729 | smp_hw_index[i] = i; | ||
730 | } | ||
727 | #endif | 731 | #endif |
728 | 732 | ||
733 | /* 32 bits SMP can't NAP */ | ||
734 | if (!machine_is_compatible("MacRISC4")) | ||
735 | powersave_nap = 0; | ||
736 | } | ||
737 | |||
729 | static int __init smp_core99_probe(void) | 738 | static int __init smp_core99_probe(void) |
730 | { | 739 | { |
731 | struct device_node *cpus; | 740 | struct device_node *cpus; |
@@ -803,17 +812,25 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr) | |||
803 | mpic_setup_this_cpu(); | 812 | mpic_setup_this_cpu(); |
804 | 813 | ||
805 | if (cpu_nr == 0) { | 814 | if (cpu_nr == 0) { |
806 | #ifdef CONFIG_POWER4 | 815 | #ifdef CONFIG_PPC64 |
807 | extern void g5_phy_disable_cpu1(void); | 816 | extern void g5_phy_disable_cpu1(void); |
808 | 817 | ||
818 | /* Close i2c bus if it was used for tb sync */ | ||
819 | if (pmac_tb_clock_chip_host) { | ||
820 | pmac_low_i2c_close(pmac_tb_clock_chip_host); | ||
821 | pmac_tb_clock_chip_host = NULL; | ||
822 | } | ||
823 | |||
809 | /* If we didn't start the second CPU, we must take | 824 | /* If we didn't start the second CPU, we must take |
810 | * it off the bus | 825 | * it off the bus |
811 | */ | 826 | */ |
812 | if (machine_is_compatible("MacRISC4") && | 827 | if (machine_is_compatible("MacRISC4") && |
813 | num_online_cpus() < 2) | 828 | num_online_cpus() < 2) |
814 | g5_phy_disable_cpu1(); | 829 | g5_phy_disable_cpu1(); |
815 | #endif /* CONFIG_POWER4 */ | 830 | #endif /* CONFIG_PPC64 */ |
816 | if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349); | 831 | |
832 | if (ppc_md.progress) | ||
833 | ppc_md.progress("core99_setup_cpu 0 done", 0x349); | ||
817 | } | 834 | } |
818 | } | 835 | } |
819 | 836 | ||