diff options
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 1cb69e8fb0b1..9a07f97f0712 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -885,6 +885,74 @@ void __init unflatten_device_tree(void) | |||
| 885 | DBG(" <- unflatten_device_tree()\n"); | 885 | DBG(" <- unflatten_device_tree()\n"); |
| 886 | } | 886 | } |
| 887 | 887 | ||
| 888 | /* | ||
| 889 | * ibm,pa-features is a per-cpu property that contains a string of | ||
| 890 | * attribute descriptors, each of which has a 2 byte header plus up | ||
| 891 | * to 254 bytes worth of processor attribute bits. First header | ||
| 892 | * byte specifies the number of bytes following the header. | ||
| 893 | * Second header byte is an "attribute-specifier" type, of which | ||
| 894 | * zero is the only currently-defined value. | ||
| 895 | * Implementation: Pass in the byte and bit offset for the feature | ||
| 896 | * that we are interested in. The function will return -1 if the | ||
| 897 | * pa-features property is missing, or a 1/0 to indicate if the feature | ||
| 898 | * is supported/not supported. Note that the bit numbers are | ||
| 899 | * big-endian to match the definition in PAPR. | ||
| 900 | */ | ||
| 901 | static struct ibm_pa_feature { | ||
| 902 | unsigned long cpu_features; /* CPU_FTR_xxx bit */ | ||
| 903 | unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */ | ||
| 904 | unsigned char pabyte; /* byte number in ibm,pa-features */ | ||
| 905 | unsigned char pabit; /* bit number (big-endian) */ | ||
| 906 | unsigned char invert; /* if 1, pa bit set => clear feature */ | ||
| 907 | } ibm_pa_features[] __initdata = { | ||
| 908 | {0, PPC_FEATURE_HAS_MMU, 0, 0, 0}, | ||
| 909 | {0, PPC_FEATURE_HAS_FPU, 0, 1, 0}, | ||
| 910 | {CPU_FTR_SLB, 0, 0, 2, 0}, | ||
| 911 | {CPU_FTR_CTRL, 0, 0, 3, 0}, | ||
| 912 | {CPU_FTR_NOEXECUTE, 0, 0, 6, 0}, | ||
| 913 | {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1}, | ||
| 914 | {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0}, | ||
| 915 | }; | ||
| 916 | |||
| 917 | static void __init check_cpu_pa_features(unsigned long node) | ||
| 918 | { | ||
| 919 | unsigned char *pa_ftrs; | ||
| 920 | unsigned long len, tablelen, i, bit; | ||
| 921 | |||
| 922 | pa_ftrs = of_get_flat_dt_prop(node, "ibm,pa-features", &tablelen); | ||
| 923 | if (pa_ftrs == NULL) | ||
| 924 | return; | ||
| 925 | |||
| 926 | /* find descriptor with type == 0 */ | ||
| 927 | for (;;) { | ||
| 928 | if (tablelen < 3) | ||
| 929 | return; | ||
| 930 | len = 2 + pa_ftrs[0]; | ||
| 931 | if (tablelen < len) | ||
| 932 | return; /* descriptor 0 not found */ | ||
| 933 | if (pa_ftrs[1] == 0) | ||
| 934 | break; | ||
| 935 | tablelen -= len; | ||
| 936 | pa_ftrs += len; | ||
| 937 | } | ||
| 938 | |||
| 939 | /* loop over bits we know about */ | ||
| 940 | for (i = 0; i < ARRAY_SIZE(ibm_pa_features); ++i) { | ||
| 941 | struct ibm_pa_feature *fp = &ibm_pa_features[i]; | ||
| 942 | |||
| 943 | if (fp->pabyte >= pa_ftrs[0]) | ||
| 944 | continue; | ||
| 945 | bit = (pa_ftrs[2 + fp->pabyte] >> (7 - fp->pabit)) & 1; | ||
| 946 | if (bit ^ fp->invert) { | ||
| 947 | cur_cpu_spec->cpu_features |= fp->cpu_features; | ||
| 948 | cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs; | ||
| 949 | } else { | ||
| 950 | cur_cpu_spec->cpu_features &= ~fp->cpu_features; | ||
| 951 | cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs; | ||
| 952 | } | ||
| 953 | } | ||
| 954 | } | ||
| 955 | |||
| 888 | static int __init early_init_dt_scan_cpus(unsigned long node, | 956 | static int __init early_init_dt_scan_cpus(unsigned long node, |
| 889 | const char *uname, int depth, | 957 | const char *uname, int depth, |
| 890 | void *data) | 958 | void *data) |
| @@ -969,6 +1037,8 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
| 969 | } | 1037 | } |
| 970 | #endif /* CONFIG_ALTIVEC */ | 1038 | #endif /* CONFIG_ALTIVEC */ |
| 971 | 1039 | ||
| 1040 | check_cpu_pa_features(node); | ||
| 1041 | |||
| 972 | #ifdef CONFIG_PPC_PSERIES | 1042 | #ifdef CONFIG_PPC_PSERIES |
| 973 | if (nthreads > 1) | 1043 | if (nthreads > 1) |
| 974 | cur_cpu_spec->cpu_features |= CPU_FTR_SMT; | 1044 | cur_cpu_spec->cpu_features |= CPU_FTR_SMT; |
