diff options
Diffstat (limited to 'arch/powerpc/kernel/cputable.c')
| -rw-r--r-- | arch/powerpc/kernel/cputable.c | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 95382f994404..bfd499ee3753 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | #include <asm/oprofile_impl.h> | 19 | #include <asm/oprofile_impl.h> |
| 20 | #include <asm/cputable.h> | 20 | #include <asm/cputable.h> |
| 21 | #include <asm/prom.h> /* for PTRRELOC on ARCH=ppc */ | ||
| 21 | 22 | ||
| 22 | struct cpu_spec* cur_cpu_spec = NULL; | 23 | struct cpu_spec* cur_cpu_spec = NULL; |
| 23 | EXPORT_SYMBOL(cur_cpu_spec); | 24 | EXPORT_SYMBOL(cur_cpu_spec); |
| @@ -73,7 +74,7 @@ extern void __restore_cpu_ppc970(void); | |||
| 73 | #define PPC_FEATURE_SPE_COMP 0 | 74 | #define PPC_FEATURE_SPE_COMP 0 |
| 74 | #endif | 75 | #endif |
| 75 | 76 | ||
| 76 | struct cpu_spec cpu_specs[] = { | 77 | static struct cpu_spec cpu_specs[] = { |
| 77 | #ifdef CONFIG_PPC64 | 78 | #ifdef CONFIG_PPC64 |
| 78 | { /* Power3 */ | 79 | { /* Power3 */ |
| 79 | .pvr_mask = 0xffff0000, | 80 | .pvr_mask = 0xffff0000, |
| @@ -227,6 +228,21 @@ struct cpu_spec cpu_specs[] = { | |||
| 227 | .oprofile_type = PPC_OPROFILE_POWER4, | 228 | .oprofile_type = PPC_OPROFILE_POWER4, |
| 228 | .platform = "ppc970", | 229 | .platform = "ppc970", |
| 229 | }, | 230 | }, |
| 231 | { /* PPC970GX */ | ||
| 232 | .pvr_mask = 0xffff0000, | ||
| 233 | .pvr_value = 0x00450000, | ||
| 234 | .cpu_name = "PPC970GX", | ||
| 235 | .cpu_features = CPU_FTRS_PPC970, | ||
| 236 | .cpu_user_features = COMMON_USER_POWER4 | | ||
| 237 | PPC_FEATURE_HAS_ALTIVEC_COMP, | ||
| 238 | .icache_bsize = 128, | ||
| 239 | .dcache_bsize = 128, | ||
| 240 | .num_pmcs = 8, | ||
| 241 | .cpu_setup = __setup_cpu_ppc970, | ||
| 242 | .oprofile_cpu_type = "ppc64/970", | ||
| 243 | .oprofile_type = PPC_OPROFILE_POWER4, | ||
| 244 | .platform = "ppc970", | ||
| 245 | }, | ||
| 230 | { /* Power5 GR */ | 246 | { /* Power5 GR */ |
| 231 | .pvr_mask = 0xffff0000, | 247 | .pvr_mask = 0xffff0000, |
| 232 | .pvr_value = 0x003a0000, | 248 | .pvr_value = 0x003a0000, |
| @@ -1152,3 +1168,71 @@ struct cpu_spec cpu_specs[] = { | |||
| 1152 | #endif /* !CLASSIC_PPC */ | 1168 | #endif /* !CLASSIC_PPC */ |
| 1153 | #endif /* CONFIG_PPC32 */ | 1169 | #endif /* CONFIG_PPC32 */ |
| 1154 | }; | 1170 | }; |
| 1171 | |||
| 1172 | struct cpu_spec *identify_cpu(unsigned long offset) | ||
| 1173 | { | ||
| 1174 | struct cpu_spec *s = cpu_specs; | ||
| 1175 | struct cpu_spec **cur = &cur_cpu_spec; | ||
| 1176 | unsigned int pvr = mfspr(SPRN_PVR); | ||
| 1177 | int i; | ||
| 1178 | |||
| 1179 | s = PTRRELOC(s); | ||
| 1180 | cur = PTRRELOC(cur); | ||
| 1181 | |||
| 1182 | if (*cur != NULL) | ||
| 1183 | return PTRRELOC(*cur); | ||
| 1184 | |||
| 1185 | for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) | ||
| 1186 | if ((pvr & s->pvr_mask) == s->pvr_value) { | ||
| 1187 | *cur = cpu_specs + i; | ||
| 1188 | #ifdef CONFIG_PPC64 | ||
| 1189 | /* ppc64 expects identify_cpu to also call setup_cpu | ||
| 1190 | * for that processor. I will consolidate that at a | ||
| 1191 | * later time, for now, just use our friend #ifdef. | ||
| 1192 | * we also don't need to PTRRELOC the function pointer | ||
| 1193 | * on ppc64 as we are running at 0 in real mode. | ||
| 1194 | */ | ||
| 1195 | if (s->cpu_setup) { | ||
| 1196 | s->cpu_setup(offset, s); | ||
| 1197 | } | ||
| 1198 | #endif /* CONFIG_PPC64 */ | ||
| 1199 | return s; | ||
| 1200 | } | ||
| 1201 | BUG(); | ||
| 1202 | return NULL; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) | ||
| 1206 | { | ||
| 1207 | struct fixup_entry { | ||
| 1208 | unsigned long mask; | ||
| 1209 | unsigned long value; | ||
| 1210 | long start_off; | ||
| 1211 | long end_off; | ||
| 1212 | } *fcur, *fend; | ||
| 1213 | |||
| 1214 | fcur = fixup_start; | ||
| 1215 | fend = fixup_end; | ||
| 1216 | |||
| 1217 | for (; fcur < fend; fcur++) { | ||
| 1218 | unsigned int *pstart, *pend, *p; | ||
| 1219 | |||
| 1220 | if ((value & fcur->mask) == fcur->value) | ||
| 1221 | continue; | ||
| 1222 | |||
| 1223 | /* These PTRRELOCs will disappear once the new scheme for | ||
| 1224 | * modules and vdso is implemented | ||
| 1225 | */ | ||
| 1226 | pstart = ((unsigned int *)fcur) + (fcur->start_off / 4); | ||
| 1227 | pend = ((unsigned int *)fcur) + (fcur->end_off / 4); | ||
| 1228 | |||
| 1229 | for (p = pstart; p < pend; p++) { | ||
| 1230 | *p = 0x60000000u; | ||
| 1231 | asm volatile ("dcbst 0, %0" : : "r" (p)); | ||
| 1232 | } | ||
| 1233 | asm volatile ("sync" : : : "memory"); | ||
| 1234 | for (p = pstart; p < pend; p++) | ||
| 1235 | asm volatile ("icbi 0,%0" : : "r" (p)); | ||
| 1236 | asm volatile ("sync; isync" : : : "memory"); | ||
| 1237 | } | ||
| 1238 | } | ||
