diff options
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r-- | arch/powerpc/kernel/prom.c | 110 |
1 files changed, 76 insertions, 34 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 16d29d16b96f..c18dbe77fdc2 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -538,35 +538,31 @@ static struct ibm_pa_feature { | |||
538 | {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, | 538 | {CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0}, |
539 | }; | 539 | }; |
540 | 540 | ||
541 | static void __init check_cpu_pa_features(unsigned long node) | 541 | static void __init scan_features(unsigned long node, unsigned char *ftrs, |
542 | unsigned long tablelen, | ||
543 | struct ibm_pa_feature *fp, | ||
544 | unsigned long ft_size) | ||
542 | { | 545 | { |
543 | unsigned char *pa_ftrs; | 546 | unsigned long i, len, bit; |
544 | unsigned long len, tablelen, i, bit; | ||
545 | |||
546 | pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen); | ||
547 | if (pa_ftrs == NULL) | ||
548 | return; | ||
549 | 547 | ||
550 | /* find descriptor with type == 0 */ | 548 | /* find descriptor with type == 0 */ |
551 | for (;;) { | 549 | for (;;) { |
552 | if (tablelen < 3) | 550 | if (tablelen < 3) |
553 | return; | 551 | return; |
554 | len = 2 + pa_ftrs[0]; | 552 | len = 2 + ftrs[0]; |
555 | if (tablelen < len) | 553 | if (tablelen < len) |
556 | return; /* descriptor 0 not found */ | 554 | return; /* descriptor 0 not found */ |
557 | if (pa_ftrs[1] == 0) | 555 | if (ftrs[1] == 0) |
558 | break; | 556 | break; |
559 | tablelen -= len; | 557 | tablelen -= len; |
560 | pa_ftrs += len; | 558 | ftrs += len; |
561 | } | 559 | } |
562 | 560 | ||
563 | /* loop over bits we know about */ | 561 | /* loop over bits we know about */ |
564 | for (i = 0; i < ARRAY_SIZE(ibm_pa_features); ++i) { | 562 | for (i = 0; i < ft_size; ++i, ++fp) { |
565 | struct ibm_pa_feature *fp = &ibm_pa_features[i]; | 563 | if (fp->pabyte >= ftrs[0]) |
566 | |||
567 | if (fp->pabyte >= pa_ftrs[0]) | ||
568 | continue; | 564 | continue; |
569 | bit = (pa_ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; | 565 | bit = (ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; |
570 | if (bit ^ fp->invert) { | 566 | if (bit ^ fp->invert) { |
571 | cur_cpu_spec->cpu_features |= fp->cpu_features; | 567 | cur_cpu_spec->cpu_features |= fp->cpu_features; |
572 | cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; | 568 | cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; |
@@ -577,16 +573,59 @@ static void __init check_cpu_pa_features(unsigned long node) | |||
577 | } | 573 | } |
578 | } | 574 | } |
579 | 575 | ||
576 | static void __init check_cpu_pa_features(unsigned long node) | ||
577 | { | ||
578 | unsigned char *pa_ftrs; | ||
579 | unsigned long tablelen; | ||
580 | |||
581 | pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen); | ||
582 | if (pa_ftrs == NULL) | ||
583 | return; | ||
584 | |||
585 | scan_features(node, pa_ftrs, tablelen, | ||
586 | ibm_pa_features, ARRAY_SIZE(ibm_pa_features)); | ||
587 | } | ||
588 | |||
589 | static struct feature_property { | ||
590 | const char *name; | ||
591 | u32 min_value; | ||
592 | unsigned long cpu_feature; | ||
593 | unsigned long cpu_user_ftr; | ||
594 | } feature_properties[] __initdata = { | ||
595 | #ifdef CONFIG_ALTIVEC | ||
596 | {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, | ||
597 | {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, | ||
598 | #endif /* CONFIG_ALTIVEC */ | ||
599 | #ifdef CONFIG_PPC64 | ||
600 | {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP}, | ||
601 | {"ibm,purr", 1, CPU_FTR_PURR, 0}, | ||
602 | {"ibm,spurr", 1, CPU_FTR_SPURR, 0}, | ||
603 | #endif /* CONFIG_PPC64 */ | ||
604 | }; | ||
605 | |||
606 | static void __init check_cpu_feature_properties(unsigned long node) | ||
607 | { | ||
608 | unsigned long i; | ||
609 | struct feature_property *fp = feature_properties; | ||
610 | const u32 *prop; | ||
611 | |||
612 | for (i = 0; i < ARRAY_SIZE(feature_properties); ++i, ++fp) { | ||
613 | prop = of_get_flat_dt_prop(node, fp->name, NULL); | ||
614 | if (prop && *prop >= fp->min_value) { | ||
615 | cur_cpu_spec->cpu_features |= fp->cpu_feature; | ||
616 | cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftr; | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | |||
580 | static int __init early_init_dt_scan_cpus(unsigned long node, | 621 | static int __init early_init_dt_scan_cpus(unsigned long node, |
581 | const char *uname, int depth, | 622 | const char *uname, int depth, |
582 | void *data) | 623 | void *data) |
583 | { | 624 | { |
584 | static int logical_cpuid = 0; | 625 | static int logical_cpuid = 0; |
585 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | 626 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); |
586 | #ifdef CONFIG_ALTIVEC | 627 | const u32 *prop; |
587 | u32 *prop; | 628 | const u32 *intserv; |
588 | #endif | ||
589 | u32 *intserv; | ||
590 | int i, nthreads; | 629 | int i, nthreads; |
591 | unsigned long len; | 630 | unsigned long len; |
592 | int found = 0; | 631 | int found = 0; |
@@ -643,24 +682,27 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
643 | intserv[i]); | 682 | intserv[i]); |
644 | boot_cpuid = logical_cpuid; | 683 | boot_cpuid = logical_cpuid; |
645 | set_hard_smp_processor_id(boot_cpuid, intserv[i]); | 684 | set_hard_smp_processor_id(boot_cpuid, intserv[i]); |
646 | } | ||
647 | 685 | ||
648 | #ifdef CONFIG_ALTIVEC | 686 | /* |
649 | /* Check if we have a VMX and eventually update CPU features */ | 687 | * PAPR defines "logical" PVR values for cpus that |
650 | prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL); | 688 | * meet various levels of the architecture: |
651 | if (prop && (*prop) > 0) { | 689 | * 0x0f000001 Architecture version 2.04 |
652 | cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; | 690 | * 0x0f000002 Architecture version 2.05 |
653 | cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; | 691 | * If the cpu-version property in the cpu node contains |
654 | } | 692 | * such a value, we call identify_cpu again with the |
655 | 693 | * logical PVR value in order to use the cpu feature | |
656 | /* Same goes for Apple's "altivec" property */ | 694 | * bits appropriate for the architecture level. |
657 | prop = (u32 *)of_get_flat_dt_prop(node, "altivec", NULL); | 695 | * |
658 | if (prop) { | 696 | * A POWER6 partition in "POWER6 architected" mode |
659 | cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC; | 697 | * uses the 0x0f000002 PVR value; in POWER5+ mode |
660 | cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; | 698 | * it uses 0x0f000001. |
699 | */ | ||
700 | prop = of_get_flat_dt_prop(node, "cpu-version", NULL); | ||
701 | if (prop && (*prop & 0xff000000) == 0x0f000000) | ||
702 | identify_cpu(0, *prop); | ||
661 | } | 703 | } |
662 | #endif /* CONFIG_ALTIVEC */ | ||
663 | 704 | ||
705 | check_cpu_feature_properties(node); | ||
664 | check_cpu_pa_features(node); | 706 | check_cpu_pa_features(node); |
665 | 707 | ||
666 | #ifdef CONFIG_PPC_PSERIES | 708 | #ifdef CONFIG_PPC_PSERIES |