Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] powerpc: Use the ibm,pa-features property if available

Forthcoming IBM machines will have a "ibm,pa-features" property on CPU
nodes, that contains bits indicating which optional architecture
features are implemented by the CPU. This adds code to use the
property, if present, to update our CPU feature bitmaps. Note that
this means we can both set and clear feature bits based on what
the firmware tells us.

This is based on a patch by Will Schmidt <willschm@us.ibm.com>.

Signed-off-by: Paul Mackerras <paulus@samba.org>

+70
+70
arch/powerpc/kernel/prom.c
··· 885 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 956 static int __init early_init_dt_scan_cpus(unsigned long node, 889 957 const char *uname, int depth, 890 958 void *data) ··· 1036 968 cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC; 1037 969 } 1038 970 #endif /* CONFIG_ALTIVEC */ 971 + 972 + check_cpu_pa_features(node); 1039 973 1040 974 #ifdef CONFIG_PPC_PSERIES 1041 975 if (nthreads > 1)