diff options
Diffstat (limited to 'arch/powerpc/kernel')
| -rw-r--r-- | arch/powerpc/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/powerpc/kernel/btext.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/cputable.c | 86 | ||||
| -rw-r--r-- | arch/powerpc/kernel/head_64.S | 48 | ||||
| -rw-r--r-- | arch/powerpc/kernel/iommu.c | 77 | ||||
| -rw-r--r-- | arch/powerpc/kernel/misc_32.S | 74 | ||||
| -rw-r--r-- | arch/powerpc/kernel/misc_64.S | 124 | ||||
| -rw-r--r-- | arch/powerpc/kernel/module_32.c | 39 | ||||
| -rw-r--r-- | arch/powerpc/kernel/module_64.c | 49 | ||||
| -rw-r--r-- | arch/powerpc/kernel/perfmon_fsl_booke.c | 221 | ||||
| -rw-r--r-- | arch/powerpc/kernel/pmc.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 8 | ||||
| -rw-r--r-- | arch/powerpc/kernel/rtas_flash.c | 47 | ||||
| -rw-r--r-- | arch/powerpc/kernel/setup_32.c | 8 | ||||
| -rw-r--r-- | arch/powerpc/kernel/setup_64.c | 11 | ||||
| -rw-r--r-- | arch/powerpc/kernel/time.c | 63 | ||||
| -rw-r--r-- | arch/powerpc/kernel/traps.c | 18 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vdso.c | 43 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vdso32/vdso32.lds.S | 12 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vdso64/gettimeofday.S | 6 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vdso64/vdso64.lds.S | 10 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vio.c | 4 | ||||
| -rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 8 |
23 files changed, 375 insertions, 586 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 8b133afbdc20..7af23c43fd4b 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
| @@ -38,7 +38,6 @@ obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o | |||
| 38 | obj-$(CONFIG_TAU) += tau_6xx.o | 38 | obj-$(CONFIG_TAU) += tau_6xx.o |
| 39 | obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o | 39 | obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o |
| 40 | obj32-$(CONFIG_MODULES) += module_32.o | 40 | obj32-$(CONFIG_MODULES) += module_32.o |
| 41 | obj-$(CONFIG_E500) += perfmon_fsl_booke.o | ||
| 42 | 41 | ||
| 43 | ifeq ($(CONFIG_PPC_MERGE),y) | 42 | ifeq ($(CONFIG_PPC_MERGE),y) |
| 44 | 43 | ||
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 995fcef156fd..93f21aaf7c8e 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c | |||
| @@ -182,7 +182,7 @@ int btext_initialize(struct device_node *np) | |||
| 182 | prop = get_property(np, "linux,bootx-linebytes", NULL); | 182 | prop = get_property(np, "linux,bootx-linebytes", NULL); |
| 183 | if (prop == NULL) | 183 | if (prop == NULL) |
| 184 | prop = get_property(np, "linebytes", NULL); | 184 | prop = get_property(np, "linebytes", NULL); |
| 185 | if (prop) | 185 | if (prop && *prop != 0xffffffffu) |
| 186 | pitch = *prop; | 186 | pitch = *prop; |
| 187 | if (pitch == 1) | 187 | if (pitch == 1) |
| 188 | pitch = 0x1000; | 188 | pitch = 0x1000; |
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 | } | ||
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 645c7f10fb28..e720729f3e55 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
| @@ -487,7 +487,7 @@ BEGIN_FTR_SECTION | |||
| 487 | rlwimi r13,r12,16,0x20 | 487 | rlwimi r13,r12,16,0x20 |
| 488 | mfcr r12 | 488 | mfcr r12 |
| 489 | cmpwi r13,0x2c | 489 | cmpwi r13,0x2c |
| 490 | beq .do_stab_bolted_pSeries | 490 | beq do_stab_bolted_pSeries |
| 491 | mtcrf 0x80,r12 | 491 | mtcrf 0x80,r12 |
| 492 | mfspr r12,SPRN_SPRG2 | 492 | mfspr r12,SPRN_SPRG2 |
| 493 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | 493 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) |
| @@ -600,7 +600,7 @@ system_call_pSeries: | |||
| 600 | STD_EXCEPTION_PSERIES(., performance_monitor) | 600 | STD_EXCEPTION_PSERIES(., performance_monitor) |
| 601 | 601 | ||
| 602 | .align 7 | 602 | .align 7 |
| 603 | _GLOBAL(do_stab_bolted_pSeries) | 603 | do_stab_bolted_pSeries: |
| 604 | mtcrf 0x80,r12 | 604 | mtcrf 0x80,r12 |
| 605 | mfspr r12,SPRN_SPRG2 | 605 | mfspr r12,SPRN_SPRG2 |
| 606 | EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) | 606 | EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) |
| @@ -1046,7 +1046,7 @@ slb_miss_fault: | |||
| 1046 | li r5,0 | 1046 | li r5,0 |
| 1047 | std r4,_DAR(r1) | 1047 | std r4,_DAR(r1) |
| 1048 | std r5,_DSISR(r1) | 1048 | std r5,_DSISR(r1) |
| 1049 | b .handle_page_fault | 1049 | b handle_page_fault |
| 1050 | 1050 | ||
| 1051 | unrecov_user_slb: | 1051 | unrecov_user_slb: |
| 1052 | EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN) | 1052 | EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN) |
| @@ -1174,12 +1174,13 @@ program_check_common: | |||
| 1174 | .globl fp_unavailable_common | 1174 | .globl fp_unavailable_common |
| 1175 | fp_unavailable_common: | 1175 | fp_unavailable_common: |
| 1176 | EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) | 1176 | EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) |
| 1177 | bne .load_up_fpu /* if from user, just load it up */ | 1177 | bne 1f /* if from user, just load it up */ |
| 1178 | bl .save_nvgprs | 1178 | bl .save_nvgprs |
| 1179 | addi r3,r1,STACK_FRAME_OVERHEAD | 1179 | addi r3,r1,STACK_FRAME_OVERHEAD |
| 1180 | ENABLE_INTS | 1180 | ENABLE_INTS |
| 1181 | bl .kernel_fp_unavailable_exception | 1181 | bl .kernel_fp_unavailable_exception |
| 1182 | BUG_OPCODE | 1182 | BUG_OPCODE |
| 1183 | 1: b .load_up_fpu | ||
| 1183 | 1184 | ||
| 1184 | .align 7 | 1185 | .align 7 |
| 1185 | .globl altivec_unavailable_common | 1186 | .globl altivec_unavailable_common |
| @@ -1279,10 +1280,10 @@ _GLOBAL(do_hash_page) | |||
| 1279 | std r4,_DSISR(r1) | 1280 | std r4,_DSISR(r1) |
| 1280 | 1281 | ||
| 1281 | andis. r0,r4,0xa450 /* weird error? */ | 1282 | andis. r0,r4,0xa450 /* weird error? */ |
| 1282 | bne- .handle_page_fault /* if not, try to insert a HPTE */ | 1283 | bne- handle_page_fault /* if not, try to insert a HPTE */ |
| 1283 | BEGIN_FTR_SECTION | 1284 | BEGIN_FTR_SECTION |
| 1284 | andis. r0,r4,0x0020 /* Is it a segment table fault? */ | 1285 | andis. r0,r4,0x0020 /* Is it a segment table fault? */ |
| 1285 | bne- .do_ste_alloc /* If so handle it */ | 1286 | bne- do_ste_alloc /* If so handle it */ |
| 1286 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | 1287 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) |
| 1287 | 1288 | ||
| 1288 | /* | 1289 | /* |
| @@ -1324,7 +1325,7 @@ BEGIN_FW_FTR_SECTION | |||
| 1324 | * because ret_from_except_lite will check for and handle pending | 1325 | * because ret_from_except_lite will check for and handle pending |
| 1325 | * interrupts if necessary. | 1326 | * interrupts if necessary. |
| 1326 | */ | 1327 | */ |
| 1327 | beq .ret_from_except_lite | 1328 | beq 13f |
| 1328 | /* For a hash failure, we don't bother re-enabling interrupts */ | 1329 | /* For a hash failure, we don't bother re-enabling interrupts */ |
| 1329 | ble- 12f | 1330 | ble- 12f |
| 1330 | 1331 | ||
| @@ -1346,14 +1347,14 @@ BEGIN_FW_FTR_SECTION | |||
| 1346 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | 1347 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) |
| 1347 | 1348 | ||
| 1348 | /* Here we have a page fault that hash_page can't handle. */ | 1349 | /* Here we have a page fault that hash_page can't handle. */ |
| 1349 | _GLOBAL(handle_page_fault) | 1350 | handle_page_fault: |
| 1350 | ENABLE_INTS | 1351 | ENABLE_INTS |
| 1351 | 11: ld r4,_DAR(r1) | 1352 | 11: ld r4,_DAR(r1) |
| 1352 | ld r5,_DSISR(r1) | 1353 | ld r5,_DSISR(r1) |
| 1353 | addi r3,r1,STACK_FRAME_OVERHEAD | 1354 | addi r3,r1,STACK_FRAME_OVERHEAD |
| 1354 | bl .do_page_fault | 1355 | bl .do_page_fault |
| 1355 | cmpdi r3,0 | 1356 | cmpdi r3,0 |
| 1356 | beq+ .ret_from_except_lite | 1357 | beq+ 13f |
| 1357 | bl .save_nvgprs | 1358 | bl .save_nvgprs |
| 1358 | mr r5,r3 | 1359 | mr r5,r3 |
| 1359 | addi r3,r1,STACK_FRAME_OVERHEAD | 1360 | addi r3,r1,STACK_FRAME_OVERHEAD |
| @@ -1370,12 +1371,14 @@ _GLOBAL(handle_page_fault) | |||
| 1370 | bl .low_hash_fault | 1371 | bl .low_hash_fault |
| 1371 | b .ret_from_except | 1372 | b .ret_from_except |
| 1372 | 1373 | ||
| 1374 | 13: b .ret_from_except_lite | ||
| 1375 | |||
| 1373 | /* here we have a segment miss */ | 1376 | /* here we have a segment miss */ |
| 1374 | _GLOBAL(do_ste_alloc) | 1377 | do_ste_alloc: |
| 1375 | bl .ste_allocate /* try to insert stab entry */ | 1378 | bl .ste_allocate /* try to insert stab entry */ |
| 1376 | cmpdi r3,0 | 1379 | cmpdi r3,0 |
| 1377 | beq+ fast_exception_return | 1380 | bne- handle_page_fault |
| 1378 | b .handle_page_fault | 1381 | b fast_exception_return |
| 1379 | 1382 | ||
| 1380 | /* | 1383 | /* |
| 1381 | * r13 points to the PACA, r9 contains the saved CR, | 1384 | * r13 points to the PACA, r9 contains the saved CR, |
| @@ -1580,11 +1583,6 @@ _STATIC(__start_initialization_iSeries) | |||
| 1580 | li r0,0 | 1583 | li r0,0 |
| 1581 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | 1584 | stdu r0,-STACK_FRAME_OVERHEAD(r1) |
| 1582 | 1585 | ||
| 1583 | LOAD_REG_IMMEDIATE(r3,cpu_specs) | ||
| 1584 | LOAD_REG_IMMEDIATE(r4,cur_cpu_spec) | ||
| 1585 | li r5,0 | ||
| 1586 | bl .identify_cpu | ||
| 1587 | |||
| 1588 | LOAD_REG_IMMEDIATE(r2,__toc_start) | 1586 | LOAD_REG_IMMEDIATE(r2,__toc_start) |
| 1589 | addi r2,r2,0x4000 | 1587 | addi r2,r2,0x4000 |
| 1590 | addi r2,r2,0x4000 | 1588 | addi r2,r2,0x4000 |
| @@ -1646,6 +1644,8 @@ _GLOBAL(__start_initialization_multiplatform) | |||
| 1646 | cmpwi r0,0x3c /* 970FX */ | 1644 | cmpwi r0,0x3c /* 970FX */ |
| 1647 | beq 1f | 1645 | beq 1f |
| 1648 | cmpwi r0,0x44 /* 970MP */ | 1646 | cmpwi r0,0x44 /* 970MP */ |
| 1647 | beq 1f | ||
| 1648 | cmpwi r0,0x45 /* 970GX */ | ||
| 1649 | bne 2f | 1649 | bne 2f |
| 1650 | 1: bl .__cpu_preinit_ppc970 | 1650 | 1: bl .__cpu_preinit_ppc970 |
| 1651 | 2: | 1651 | 2: |
| @@ -1964,13 +1964,6 @@ _STATIC(start_here_multiplatform) | |||
| 1964 | addi r2,r2,0x4000 | 1964 | addi r2,r2,0x4000 |
| 1965 | add r2,r2,r26 | 1965 | add r2,r2,r26 |
| 1966 | 1966 | ||
| 1967 | LOAD_REG_IMMEDIATE(r3, cpu_specs) | ||
| 1968 | add r3,r3,r26 | ||
| 1969 | LOAD_REG_IMMEDIATE(r4,cur_cpu_spec) | ||
| 1970 | add r4,r4,r26 | ||
| 1971 | mr r5,r26 | ||
| 1972 | bl .identify_cpu | ||
| 1973 | |||
| 1974 | /* Do very early kernel initializations, including initial hash table, | 1967 | /* Do very early kernel initializations, including initial hash table, |
| 1975 | * stab and slb setup before we turn on relocation. */ | 1968 | * stab and slb setup before we turn on relocation. */ |
| 1976 | 1969 | ||
| @@ -2000,13 +1993,6 @@ _STATIC(start_here_common) | |||
| 2000 | li r0,0 | 1993 | li r0,0 |
| 2001 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | 1994 | stdu r0,-STACK_FRAME_OVERHEAD(r1) |
| 2002 | 1995 | ||
| 2003 | /* Apply the CPUs-specific fixups (nop out sections not relevant | ||
| 2004 | * to this CPU | ||
| 2005 | */ | ||
| 2006 | li r3,0 | ||
| 2007 | bl .do_cpu_ftr_fixups | ||
| 2008 | bl .do_fw_ftr_fixups | ||
| 2009 | |||
| 2010 | /* ptr to current */ | 1996 | /* ptr to current */ |
| 2011 | LOAD_REG_IMMEDIATE(r4, init_task) | 1997 | LOAD_REG_IMMEDIATE(r4, init_task) |
| 2012 | std r4,PACACURRENT(r13) | 1998 | std r4,PACACURRENT(r13) |
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index f88a2a675d90..ba6b7256084b 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
| @@ -47,6 +47,17 @@ static int novmerge = 0; | |||
| 47 | static int novmerge = 1; | 47 | static int novmerge = 1; |
| 48 | #endif | 48 | #endif |
| 49 | 49 | ||
| 50 | static inline unsigned long iommu_num_pages(unsigned long vaddr, | ||
| 51 | unsigned long slen) | ||
| 52 | { | ||
| 53 | unsigned long npages; | ||
| 54 | |||
| 55 | npages = IOMMU_PAGE_ALIGN(vaddr + slen) - (vaddr & IOMMU_PAGE_MASK); | ||
| 56 | npages >>= IOMMU_PAGE_SHIFT; | ||
| 57 | |||
| 58 | return npages; | ||
| 59 | } | ||
| 60 | |||
| 50 | static int __init setup_iommu(char *str) | 61 | static int __init setup_iommu(char *str) |
| 51 | { | 62 | { |
| 52 | if (!strcmp(str, "novmerge")) | 63 | if (!strcmp(str, "novmerge")) |
| @@ -178,10 +189,10 @@ static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page, | |||
| 178 | } | 189 | } |
| 179 | 190 | ||
| 180 | entry += tbl->it_offset; /* Offset into real TCE table */ | 191 | entry += tbl->it_offset; /* Offset into real TCE table */ |
| 181 | ret = entry << PAGE_SHIFT; /* Set the return dma address */ | 192 | ret = entry << IOMMU_PAGE_SHIFT; /* Set the return dma address */ |
| 182 | 193 | ||
| 183 | /* Put the TCEs in the HW table */ | 194 | /* Put the TCEs in the HW table */ |
| 184 | ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & PAGE_MASK, | 195 | ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & IOMMU_PAGE_MASK, |
| 185 | direction); | 196 | direction); |
| 186 | 197 | ||
| 187 | 198 | ||
| @@ -203,7 +214,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
| 203 | unsigned long entry, free_entry; | 214 | unsigned long entry, free_entry; |
| 204 | unsigned long i; | 215 | unsigned long i; |
| 205 | 216 | ||
| 206 | entry = dma_addr >> PAGE_SHIFT; | 217 | entry = dma_addr >> IOMMU_PAGE_SHIFT; |
| 207 | free_entry = entry - tbl->it_offset; | 218 | free_entry = entry - tbl->it_offset; |
| 208 | 219 | ||
| 209 | if (((free_entry + npages) > tbl->it_size) || | 220 | if (((free_entry + npages) > tbl->it_size) || |
| @@ -270,7 +281,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
| 270 | /* Init first segment length for backout at failure */ | 281 | /* Init first segment length for backout at failure */ |
| 271 | outs->dma_length = 0; | 282 | outs->dma_length = 0; |
| 272 | 283 | ||
| 273 | DBG("mapping %d elements:\n", nelems); | 284 | DBG("sg mapping %d elements:\n", nelems); |
| 274 | 285 | ||
| 275 | spin_lock_irqsave(&(tbl->it_lock), flags); | 286 | spin_lock_irqsave(&(tbl->it_lock), flags); |
| 276 | 287 | ||
| @@ -285,9 +296,8 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
| 285 | } | 296 | } |
| 286 | /* Allocate iommu entries for that segment */ | 297 | /* Allocate iommu entries for that segment */ |
| 287 | vaddr = (unsigned long)page_address(s->page) + s->offset; | 298 | vaddr = (unsigned long)page_address(s->page) + s->offset; |
| 288 | npages = PAGE_ALIGN(vaddr + slen) - (vaddr & PAGE_MASK); | 299 | npages = iommu_num_pages(vaddr, slen); |
| 289 | npages >>= PAGE_SHIFT; | 300 | entry = iommu_range_alloc(tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, 0); |
| 290 | entry = iommu_range_alloc(tbl, npages, &handle, mask >> PAGE_SHIFT, 0); | ||
| 291 | 301 | ||
| 292 | DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); | 302 | DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); |
| 293 | 303 | ||
| @@ -301,14 +311,14 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
| 301 | 311 | ||
| 302 | /* Convert entry to a dma_addr_t */ | 312 | /* Convert entry to a dma_addr_t */ |
| 303 | entry += tbl->it_offset; | 313 | entry += tbl->it_offset; |
| 304 | dma_addr = entry << PAGE_SHIFT; | 314 | dma_addr = entry << IOMMU_PAGE_SHIFT; |
| 305 | dma_addr |= s->offset; | 315 | dma_addr |= (s->offset & ~IOMMU_PAGE_MASK); |
| 306 | 316 | ||
| 307 | DBG(" - %lx pages, entry: %lx, dma_addr: %lx\n", | 317 | DBG(" - %lu pages, entry: %lx, dma_addr: %lx\n", |
| 308 | npages, entry, dma_addr); | 318 | npages, entry, dma_addr); |
| 309 | 319 | ||
| 310 | /* Insert into HW table */ | 320 | /* Insert into HW table */ |
| 311 | ppc_md.tce_build(tbl, entry, npages, vaddr & PAGE_MASK, direction); | 321 | ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction); |
| 312 | 322 | ||
| 313 | /* If we are in an open segment, try merging */ | 323 | /* If we are in an open segment, try merging */ |
| 314 | if (segstart != s) { | 324 | if (segstart != s) { |
| @@ -323,7 +333,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
| 323 | DBG(" can't merge, new segment.\n"); | 333 | DBG(" can't merge, new segment.\n"); |
| 324 | } else { | 334 | } else { |
| 325 | outs->dma_length += s->length; | 335 | outs->dma_length += s->length; |
| 326 | DBG(" merged, new len: %lx\n", outs->dma_length); | 336 | DBG(" merged, new len: %ux\n", outs->dma_length); |
| 327 | } | 337 | } |
| 328 | } | 338 | } |
| 329 | 339 | ||
| @@ -367,9 +377,8 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | |||
| 367 | if (s->dma_length != 0) { | 377 | if (s->dma_length != 0) { |
| 368 | unsigned long vaddr, npages; | 378 | unsigned long vaddr, npages; |
| 369 | 379 | ||
| 370 | vaddr = s->dma_address & PAGE_MASK; | 380 | vaddr = s->dma_address & IOMMU_PAGE_MASK; |
| 371 | npages = (PAGE_ALIGN(s->dma_address + s->dma_length) - vaddr) | 381 | npages = iommu_num_pages(s->dma_address, s->dma_length); |
| 372 | >> PAGE_SHIFT; | ||
| 373 | __iommu_free(tbl, vaddr, npages); | 382 | __iommu_free(tbl, vaddr, npages); |
| 374 | s->dma_address = DMA_ERROR_CODE; | 383 | s->dma_address = DMA_ERROR_CODE; |
| 375 | s->dma_length = 0; | 384 | s->dma_length = 0; |
| @@ -398,8 +407,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
| 398 | 407 | ||
| 399 | if (sglist->dma_length == 0) | 408 | if (sglist->dma_length == 0) |
| 400 | break; | 409 | break; |
| 401 | npages = (PAGE_ALIGN(dma_handle + sglist->dma_length) | 410 | npages = iommu_num_pages(dma_handle,sglist->dma_length); |
| 402 | - (dma_handle & PAGE_MASK)) >> PAGE_SHIFT; | ||
| 403 | __iommu_free(tbl, dma_handle, npages); | 411 | __iommu_free(tbl, dma_handle, npages); |
| 404 | sglist++; | 412 | sglist++; |
| 405 | } | 413 | } |
| @@ -532,12 +540,11 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, | |||
| 532 | BUG_ON(direction == DMA_NONE); | 540 | BUG_ON(direction == DMA_NONE); |
| 533 | 541 | ||
| 534 | uaddr = (unsigned long)vaddr; | 542 | uaddr = (unsigned long)vaddr; |
| 535 | npages = PAGE_ALIGN(uaddr + size) - (uaddr & PAGE_MASK); | 543 | npages = iommu_num_pages(uaddr, size); |
| 536 | npages >>= PAGE_SHIFT; | ||
| 537 | 544 | ||
| 538 | if (tbl) { | 545 | if (tbl) { |
| 539 | dma_handle = iommu_alloc(tbl, vaddr, npages, direction, | 546 | dma_handle = iommu_alloc(tbl, vaddr, npages, direction, |
| 540 | mask >> PAGE_SHIFT, 0); | 547 | mask >> IOMMU_PAGE_SHIFT, 0); |
| 541 | if (dma_handle == DMA_ERROR_CODE) { | 548 | if (dma_handle == DMA_ERROR_CODE) { |
| 542 | if (printk_ratelimit()) { | 549 | if (printk_ratelimit()) { |
| 543 | printk(KERN_INFO "iommu_alloc failed, " | 550 | printk(KERN_INFO "iommu_alloc failed, " |
| @@ -545,7 +552,7 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, | |||
| 545 | tbl, vaddr, npages); | 552 | tbl, vaddr, npages); |
| 546 | } | 553 | } |
| 547 | } else | 554 | } else |
| 548 | dma_handle |= (uaddr & ~PAGE_MASK); | 555 | dma_handle |= (uaddr & ~IOMMU_PAGE_MASK); |
| 549 | } | 556 | } |
| 550 | 557 | ||
| 551 | return dma_handle; | 558 | return dma_handle; |
| @@ -554,11 +561,14 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, | |||
| 554 | void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, | 561 | void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, |
| 555 | size_t size, enum dma_data_direction direction) | 562 | size_t size, enum dma_data_direction direction) |
| 556 | { | 563 | { |
| 564 | unsigned int npages; | ||
| 565 | |||
| 557 | BUG_ON(direction == DMA_NONE); | 566 | BUG_ON(direction == DMA_NONE); |
| 558 | 567 | ||
| 559 | if (tbl) | 568 | if (tbl) { |
| 560 | iommu_free(tbl, dma_handle, (PAGE_ALIGN(dma_handle + size) - | 569 | npages = iommu_num_pages(dma_handle, size); |
| 561 | (dma_handle & PAGE_MASK)) >> PAGE_SHIFT); | 570 | iommu_free(tbl, dma_handle, npages); |
| 571 | } | ||
| 562 | } | 572 | } |
| 563 | 573 | ||
| 564 | /* Allocates a contiguous real buffer and creates mappings over it. | 574 | /* Allocates a contiguous real buffer and creates mappings over it. |
| @@ -570,11 +580,11 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, | |||
| 570 | { | 580 | { |
| 571 | void *ret = NULL; | 581 | void *ret = NULL; |
| 572 | dma_addr_t mapping; | 582 | dma_addr_t mapping; |
| 573 | unsigned int npages, order; | 583 | unsigned int order; |
| 584 | unsigned int nio_pages, io_order; | ||
| 574 | struct page *page; | 585 | struct page *page; |
| 575 | 586 | ||
| 576 | size = PAGE_ALIGN(size); | 587 | size = PAGE_ALIGN(size); |
| 577 | npages = size >> PAGE_SHIFT; | ||
| 578 | order = get_order(size); | 588 | order = get_order(size); |
| 579 | 589 | ||
| 580 | /* | 590 | /* |
| @@ -598,8 +608,10 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, | |||
| 598 | memset(ret, 0, size); | 608 | memset(ret, 0, size); |
| 599 | 609 | ||
| 600 | /* Set up tces to cover the allocated range */ | 610 | /* Set up tces to cover the allocated range */ |
| 601 | mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL, | 611 | nio_pages = size >> IOMMU_PAGE_SHIFT; |
| 602 | mask >> PAGE_SHIFT, order); | 612 | io_order = get_iommu_order(size); |
| 613 | mapping = iommu_alloc(tbl, ret, nio_pages, DMA_BIDIRECTIONAL, | ||
| 614 | mask >> IOMMU_PAGE_SHIFT, io_order); | ||
| 603 | if (mapping == DMA_ERROR_CODE) { | 615 | if (mapping == DMA_ERROR_CODE) { |
| 604 | free_pages((unsigned long)ret, order); | 616 | free_pages((unsigned long)ret, order); |
| 605 | return NULL; | 617 | return NULL; |
| @@ -611,12 +623,13 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, | |||
| 611 | void iommu_free_coherent(struct iommu_table *tbl, size_t size, | 623 | void iommu_free_coherent(struct iommu_table *tbl, size_t size, |
| 612 | void *vaddr, dma_addr_t dma_handle) | 624 | void *vaddr, dma_addr_t dma_handle) |
| 613 | { | 625 | { |
| 614 | unsigned int npages; | ||
| 615 | |||
| 616 | if (tbl) { | 626 | if (tbl) { |
| 627 | unsigned int nio_pages; | ||
| 628 | |||
| 629 | size = PAGE_ALIGN(size); | ||
| 630 | nio_pages = size >> IOMMU_PAGE_SHIFT; | ||
| 631 | iommu_free(tbl, dma_handle, nio_pages); | ||
| 617 | size = PAGE_ALIGN(size); | 632 | size = PAGE_ALIGN(size); |
| 618 | npages = size >> PAGE_SHIFT; | ||
| 619 | iommu_free(tbl, dma_handle, npages); | ||
| 620 | free_pages((unsigned long)vaddr, get_order(size)); | 633 | free_pages((unsigned long)vaddr, get_order(size)); |
| 621 | } | 634 | } |
| 622 | } | 635 | } |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 88fd73fdf048..412bea3cf813 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
| @@ -102,80 +102,6 @@ _GLOBAL(reloc_got2) | |||
| 102 | blr | 102 | blr |
| 103 | 103 | ||
| 104 | /* | 104 | /* |
| 105 | * identify_cpu, | ||
| 106 | * called with r3 = data offset and r4 = CPU number | ||
| 107 | * doesn't change r3 | ||
| 108 | */ | ||
| 109 | _GLOBAL(identify_cpu) | ||
| 110 | addis r8,r3,cpu_specs@ha | ||
| 111 | addi r8,r8,cpu_specs@l | ||
| 112 | mfpvr r7 | ||
| 113 | 1: | ||
| 114 | lwz r5,CPU_SPEC_PVR_MASK(r8) | ||
| 115 | and r5,r5,r7 | ||
| 116 | lwz r6,CPU_SPEC_PVR_VALUE(r8) | ||
| 117 | cmplw 0,r6,r5 | ||
| 118 | beq 1f | ||
| 119 | addi r8,r8,CPU_SPEC_ENTRY_SIZE | ||
| 120 | b 1b | ||
| 121 | 1: | ||
| 122 | addis r6,r3,cur_cpu_spec@ha | ||
| 123 | addi r6,r6,cur_cpu_spec@l | ||
| 124 | sub r8,r8,r3 | ||
| 125 | stw r8,0(r6) | ||
| 126 | blr | ||
| 127 | |||
| 128 | /* | ||
| 129 | * do_cpu_ftr_fixups - goes through the list of CPU feature fixups | ||
| 130 | * and writes nop's over sections of code that don't apply for this cpu. | ||
| 131 | * r3 = data offset (not changed) | ||
| 132 | */ | ||
| 133 | _GLOBAL(do_cpu_ftr_fixups) | ||
| 134 | /* Get CPU 0 features */ | ||
| 135 | addis r6,r3,cur_cpu_spec@ha | ||
| 136 | addi r6,r6,cur_cpu_spec@l | ||
| 137 | lwz r4,0(r6) | ||
| 138 | add r4,r4,r3 | ||
| 139 | lwz r4,CPU_SPEC_FEATURES(r4) | ||
| 140 | |||
| 141 | /* Get the fixup table */ | ||
| 142 | addis r6,r3,__start___ftr_fixup@ha | ||
| 143 | addi r6,r6,__start___ftr_fixup@l | ||
| 144 | addis r7,r3,__stop___ftr_fixup@ha | ||
| 145 | addi r7,r7,__stop___ftr_fixup@l | ||
| 146 | |||
| 147 | /* Do the fixup */ | ||
| 148 | 1: cmplw 0,r6,r7 | ||
| 149 | bgelr | ||
| 150 | addi r6,r6,16 | ||
| 151 | lwz r8,-16(r6) /* mask */ | ||
| 152 | and r8,r8,r4 | ||
| 153 | lwz r9,-12(r6) /* value */ | ||
| 154 | cmplw 0,r8,r9 | ||
| 155 | beq 1b | ||
| 156 | lwz r8,-8(r6) /* section begin */ | ||
| 157 | lwz r9,-4(r6) /* section end */ | ||
| 158 | subf. r9,r8,r9 | ||
| 159 | beq 1b | ||
| 160 | /* write nops over the section of code */ | ||
| 161 | /* todo: if large section, add a branch at the start of it */ | ||
| 162 | srwi r9,r9,2 | ||
| 163 | mtctr r9 | ||
| 164 | add r8,r8,r3 | ||
| 165 | lis r0,0x60000000@h /* nop */ | ||
| 166 | 3: stw r0,0(r8) | ||
| 167 | andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l | ||
| 168 | beq 2f | ||
| 169 | dcbst 0,r8 /* suboptimal, but simpler */ | ||
| 170 | sync | ||
| 171 | icbi 0,r8 | ||
| 172 | 2: addi r8,r8,4 | ||
| 173 | bdnz 3b | ||
| 174 | sync /* additional sync needed on g4 */ | ||
| 175 | isync | ||
| 176 | b 1b | ||
| 177 | |||
| 178 | /* | ||
| 179 | * call_setup_cpu - call the setup_cpu function for this cpu | 105 | * call_setup_cpu - call the setup_cpu function for this cpu |
| 180 | * r3 = data offset, r24 = cpu number | 106 | * r3 = data offset, r24 = cpu number |
| 181 | * | 107 | * |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index c70e20708a1f..21fd2c662a99 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
| @@ -246,130 +246,6 @@ _GLOBAL(__flush_dcache_icache) | |||
| 246 | isync | 246 | isync |
| 247 | blr | 247 | blr |
| 248 | 248 | ||
| 249 | /* | ||
| 250 | * identify_cpu and calls setup_cpu | ||
| 251 | * In: r3 = base of the cpu_specs array | ||
| 252 | * r4 = address of cur_cpu_spec | ||
| 253 | * r5 = relocation offset | ||
| 254 | */ | ||
| 255 | _GLOBAL(identify_cpu) | ||
| 256 | mfpvr r7 | ||
| 257 | 1: | ||
| 258 | lwz r8,CPU_SPEC_PVR_MASK(r3) | ||
| 259 | and r8,r8,r7 | ||
| 260 | lwz r9,CPU_SPEC_PVR_VALUE(r3) | ||
| 261 | cmplw 0,r9,r8 | ||
| 262 | beq 1f | ||
| 263 | addi r3,r3,CPU_SPEC_ENTRY_SIZE | ||
| 264 | b 1b | ||
| 265 | 1: | ||
| 266 | sub r0,r3,r5 | ||
| 267 | std r0,0(r4) | ||
| 268 | ld r4,CPU_SPEC_SETUP(r3) | ||
| 269 | cmpdi 0,r4,0 | ||
| 270 | add r4,r4,r5 | ||
| 271 | beqlr | ||
| 272 | ld r4,0(r4) | ||
| 273 | add r4,r4,r5 | ||
| 274 | mtctr r4 | ||
| 275 | /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */ | ||
| 276 | mr r4,r3 | ||
| 277 | mr r3,r5 | ||
| 278 | bctr | ||
| 279 | |||
| 280 | /* | ||
| 281 | * do_cpu_ftr_fixups - goes through the list of CPU feature fixups | ||
| 282 | * and writes nop's over sections of code that don't apply for this cpu. | ||
| 283 | * r3 = data offset (not changed) | ||
| 284 | */ | ||
| 285 | _GLOBAL(do_cpu_ftr_fixups) | ||
| 286 | /* Get CPU 0 features */ | ||
| 287 | LOAD_REG_IMMEDIATE(r6,cur_cpu_spec) | ||
| 288 | sub r6,r6,r3 | ||
| 289 | ld r4,0(r6) | ||
| 290 | sub r4,r4,r3 | ||
| 291 | ld r4,CPU_SPEC_FEATURES(r4) | ||
| 292 | /* Get the fixup table */ | ||
| 293 | LOAD_REG_IMMEDIATE(r6,__start___ftr_fixup) | ||
| 294 | sub r6,r6,r3 | ||
| 295 | LOAD_REG_IMMEDIATE(r7,__stop___ftr_fixup) | ||
| 296 | sub r7,r7,r3 | ||
| 297 | /* Do the fixup */ | ||
| 298 | 1: cmpld r6,r7 | ||
| 299 | bgelr | ||
| 300 | addi r6,r6,32 | ||
| 301 | ld r8,-32(r6) /* mask */ | ||
| 302 | and r8,r8,r4 | ||
| 303 | ld r9,-24(r6) /* value */ | ||
| 304 | cmpld r8,r9 | ||
| 305 | beq 1b | ||
| 306 | ld r8,-16(r6) /* section begin */ | ||
| 307 | ld r9,-8(r6) /* section end */ | ||
| 308 | subf. r9,r8,r9 | ||
| 309 | beq 1b | ||
| 310 | /* write nops over the section of code */ | ||
| 311 | /* todo: if large section, add a branch at the start of it */ | ||
| 312 | srwi r9,r9,2 | ||
| 313 | mtctr r9 | ||
| 314 | sub r8,r8,r3 | ||
| 315 | lis r0,0x60000000@h /* nop */ | ||
| 316 | 3: stw r0,0(r8) | ||
| 317 | andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l | ||
| 318 | beq 2f | ||
| 319 | dcbst 0,r8 /* suboptimal, but simpler */ | ||
| 320 | sync | ||
| 321 | icbi 0,r8 | ||
| 322 | 2: addi r8,r8,4 | ||
| 323 | bdnz 3b | ||
| 324 | sync /* additional sync needed on g4 */ | ||
| 325 | isync | ||
| 326 | b 1b | ||
| 327 | |||
| 328 | /* | ||
| 329 | * do_fw_ftr_fixups - goes through the list of firmware feature fixups | ||
| 330 | * and writes nop's over sections of code that don't apply for this firmware. | ||
| 331 | * r3 = data offset (not changed) | ||
| 332 | */ | ||
| 333 | _GLOBAL(do_fw_ftr_fixups) | ||
| 334 | /* Get firmware features */ | ||
| 335 | LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features) | ||
| 336 | sub r6,r6,r3 | ||
| 337 | ld r4,0(r6) | ||
| 338 | /* Get the fixup table */ | ||
| 339 | LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup) | ||
| 340 | sub r6,r6,r3 | ||
| 341 | LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup) | ||
| 342 | sub r7,r7,r3 | ||
| 343 | /* Do the fixup */ | ||
| 344 | 1: cmpld r6,r7 | ||
| 345 | bgelr | ||
| 346 | addi r6,r6,32 | ||
| 347 | ld r8,-32(r6) /* mask */ | ||
| 348 | and r8,r8,r4 | ||
| 349 | ld r9,-24(r6) /* value */ | ||
| 350 | cmpld r8,r9 | ||
| 351 | beq 1b | ||
| 352 | ld r8,-16(r6) /* section begin */ | ||
| 353 | ld r9,-8(r6) /* section end */ | ||
| 354 | subf. r9,r8,r9 | ||
| 355 | beq 1b | ||
| 356 | /* write nops over the section of code */ | ||
| 357 | /* todo: if large section, add a branch at the start of it */ | ||
| 358 | srwi r9,r9,2 | ||
| 359 | mtctr r9 | ||
| 360 | sub r8,r8,r3 | ||
| 361 | lis r0,0x60000000@h /* nop */ | ||
| 362 | 3: stw r0,0(r8) | ||
| 363 | BEGIN_FTR_SECTION | ||
| 364 | dcbst 0,r8 /* suboptimal, but simpler */ | ||
| 365 | sync | ||
| 366 | icbi 0,r8 | ||
| 367 | END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE) | ||
| 368 | addi r8,r8,4 | ||
| 369 | bdnz 3b | ||
| 370 | sync /* additional sync needed on g4 */ | ||
| 371 | isync | ||
| 372 | b 1b | ||
| 373 | 249 | ||
| 374 | #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) | 250 | #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) |
| 375 | /* | 251 | /* |
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 92f4e5f64f02..e2c3c6a85f33 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
| 25 | #include <linux/cache.h> | 25 | #include <linux/cache.h> |
| 26 | 26 | ||
| 27 | #include "setup.h" | ||
| 28 | |||
| 27 | #if 0 | 29 | #if 0 |
| 28 | #define DEBUGP printk | 30 | #define DEBUGP printk |
| 29 | #else | 31 | #else |
| @@ -269,33 +271,50 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, | |||
| 269 | return 0; | 271 | return 0; |
| 270 | } | 272 | } |
| 271 | 273 | ||
| 274 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, | ||
| 275 | const Elf_Shdr *sechdrs, | ||
| 276 | const char *name) | ||
| 277 | { | ||
| 278 | char *secstrings; | ||
| 279 | unsigned int i; | ||
| 280 | |||
| 281 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
| 282 | for (i = 1; i < hdr->e_shnum; i++) | ||
| 283 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) | ||
| 284 | return &sechdrs[i]; | ||
| 285 | return NULL; | ||
| 286 | } | ||
| 287 | |||
| 272 | int module_finalize(const Elf_Ehdr *hdr, | 288 | int module_finalize(const Elf_Ehdr *hdr, |
| 273 | const Elf_Shdr *sechdrs, | 289 | const Elf_Shdr *sechdrs, |
| 274 | struct module *me) | 290 | struct module *me) |
| 275 | { | 291 | { |
| 276 | char *secstrings; | 292 | const Elf_Shdr *sect; |
| 277 | unsigned int i; | ||
| 278 | 293 | ||
| 279 | me->arch.bug_table = NULL; | 294 | me->arch.bug_table = NULL; |
| 280 | me->arch.num_bugs = 0; | 295 | me->arch.num_bugs = 0; |
| 281 | 296 | ||
| 282 | /* Find the __bug_table section, if present */ | 297 | /* Find the __bug_table section, if present */ |
| 283 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 298 | sect = find_section(hdr, sechdrs, "__bug_table"); |
| 284 | for (i = 1; i < hdr->e_shnum; i++) { | 299 | if (sect != NULL) { |
| 285 | if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) | 300 | me->arch.bug_table = (void *) sect->sh_addr; |
| 286 | continue; | 301 | me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry); |
| 287 | me->arch.bug_table = (void *) sechdrs[i].sh_addr; | ||
| 288 | me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); | ||
| 289 | break; | ||
| 290 | } | 302 | } |
| 291 | 303 | ||
| 292 | /* | 304 | /* |
| 293 | * Strictly speaking this should have a spinlock to protect against | 305 | * Strictly speaking this should have a spinlock to protect against |
| 294 | * traversals, but since we only traverse on BUG()s, a spinlock | 306 | * traversals, but since we only traverse on BUG()s, a spinlock |
| 295 | * could potentially lead to deadlock and thus be counter-productive. | 307 | * could potentially lead to deadlock and thus be counter-productive. |
| 296 | */ | 308 | */ |
| 297 | list_add(&me->arch.bug_list, &module_bug_list); | 309 | list_add(&me->arch.bug_list, &module_bug_list); |
| 298 | 310 | ||
| 311 | /* Apply feature fixups */ | ||
| 312 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | ||
| 313 | if (sect != NULL) | ||
| 314 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
| 315 | (void *)sect->sh_addr, | ||
| 316 | (void *)sect->sh_addr + sect->sh_size); | ||
| 317 | |||
| 299 | return 0; | 318 | return 0; |
| 300 | } | 319 | } |
| 301 | 320 | ||
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index ba34001fca8e..8dd1f0aae5d6 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c | |||
| @@ -22,6 +22,9 @@ | |||
| 22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
| 23 | #include <asm/module.h> | 23 | #include <asm/module.h> |
| 24 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
| 25 | #include <asm/firmware.h> | ||
| 26 | |||
| 27 | #include "setup.h" | ||
| 25 | 28 | ||
| 26 | /* FIXME: We don't do .init separately. To do this, we'd need to have | 29 | /* FIXME: We don't do .init separately. To do this, we'd need to have |
| 27 | a separate r2 value in the init and core section, and stub between | 30 | a separate r2 value in the init and core section, and stub between |
| @@ -400,6 +403,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
| 400 | | (value & 0x03fffffc); | 403 | | (value & 0x03fffffc); |
| 401 | break; | 404 | break; |
| 402 | 405 | ||
| 406 | case R_PPC64_REL64: | ||
| 407 | /* 64 bits relative (used by features fixups) */ | ||
| 408 | *location = value - (unsigned long)location; | ||
| 409 | break; | ||
| 410 | |||
| 403 | default: | 411 | default: |
| 404 | printk("%s: Unknown ADD relocation: %lu\n", | 412 | printk("%s: Unknown ADD relocation: %lu\n", |
| 405 | me->name, | 413 | me->name, |
| @@ -413,23 +421,33 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
| 413 | 421 | ||
| 414 | LIST_HEAD(module_bug_list); | 422 | LIST_HEAD(module_bug_list); |
| 415 | 423 | ||
| 416 | int module_finalize(const Elf_Ehdr *hdr, | 424 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, |
| 417 | const Elf_Shdr *sechdrs, struct module *me) | 425 | const Elf_Shdr *sechdrs, |
| 426 | const char *name) | ||
| 418 | { | 427 | { |
| 419 | char *secstrings; | 428 | char *secstrings; |
| 420 | unsigned int i; | 429 | unsigned int i; |
| 421 | 430 | ||
| 431 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
| 432 | for (i = 1; i < hdr->e_shnum; i++) | ||
| 433 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) | ||
| 434 | return &sechdrs[i]; | ||
| 435 | return NULL; | ||
| 436 | } | ||
| 437 | |||
| 438 | int module_finalize(const Elf_Ehdr *hdr, | ||
| 439 | const Elf_Shdr *sechdrs, struct module *me) | ||
| 440 | { | ||
| 441 | const Elf_Shdr *sect; | ||
| 442 | |||
| 422 | me->arch.bug_table = NULL; | 443 | me->arch.bug_table = NULL; |
| 423 | me->arch.num_bugs = 0; | 444 | me->arch.num_bugs = 0; |
| 424 | 445 | ||
| 425 | /* Find the __bug_table section, if present */ | 446 | /* Find the __bug_table section, if present */ |
| 426 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 447 | sect = find_section(hdr, sechdrs, "__bug_table"); |
| 427 | for (i = 1; i < hdr->e_shnum; i++) { | 448 | if (sect != NULL) { |
| 428 | if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) | 449 | me->arch.bug_table = (void *) sect->sh_addr; |
| 429 | continue; | 450 | me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry); |
| 430 | me->arch.bug_table = (void *) sechdrs[i].sh_addr; | ||
| 431 | me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); | ||
| 432 | break; | ||
| 433 | } | 451 | } |
| 434 | 452 | ||
| 435 | /* | 453 | /* |
| @@ -439,6 +457,19 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
| 439 | */ | 457 | */ |
| 440 | list_add(&me->arch.bug_list, &module_bug_list); | 458 | list_add(&me->arch.bug_list, &module_bug_list); |
| 441 | 459 | ||
| 460 | /* Apply feature fixups */ | ||
| 461 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | ||
| 462 | if (sect != NULL) | ||
| 463 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
| 464 | (void *)sect->sh_addr, | ||
| 465 | (void *)sect->sh_addr + sect->sh_size); | ||
| 466 | |||
| 467 | sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); | ||
| 468 | if (sect != NULL) | ||
| 469 | do_feature_fixups(powerpc_firmware_features, | ||
| 470 | (void *)sect->sh_addr, | ||
| 471 | (void *)sect->sh_addr + sect->sh_size); | ||
| 472 | |||
| 442 | return 0; | 473 | return 0; |
| 443 | } | 474 | } |
| 444 | 475 | ||
diff --git a/arch/powerpc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c deleted file mode 100644 index e0dcf2b41fbe..000000000000 --- a/arch/powerpc/kernel/perfmon_fsl_booke.c +++ /dev/null | |||
| @@ -1,221 +0,0 @@ | |||
| 1 | /* arch/powerpc/kernel/perfmon_fsl_booke.c | ||
| 2 | * Freescale Book-E Performance Monitor code | ||
| 3 | * | ||
| 4 | * Author: Andy Fleming | ||
| 5 | * Copyright (c) 2004 Freescale Semiconductor, Inc | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version | ||
| 10 | * 2 of the License, or (at your option) any later version. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/errno.h> | ||
| 14 | #include <linux/sched.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/mm.h> | ||
| 17 | #include <linux/stddef.h> | ||
| 18 | #include <linux/unistd.h> | ||
| 19 | #include <linux/ptrace.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/user.h> | ||
| 22 | #include <linux/a.out.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/prctl.h> | ||
| 27 | |||
| 28 | #include <asm/pgtable.h> | ||
| 29 | #include <asm/uaccess.h> | ||
| 30 | #include <asm/system.h> | ||
| 31 | #include <asm/io.h> | ||
| 32 | #include <asm/reg.h> | ||
| 33 | #include <asm/xmon.h> | ||
| 34 | #include <asm/pmc.h> | ||
| 35 | |||
| 36 | static inline u32 get_pmlca(int ctr); | ||
| 37 | static inline void set_pmlca(int ctr, u32 pmlca); | ||
| 38 | |||
| 39 | static inline u32 get_pmlca(int ctr) | ||
| 40 | { | ||
| 41 | u32 pmlca; | ||
| 42 | |||
| 43 | switch (ctr) { | ||
| 44 | case 0: | ||
| 45 | pmlca = mfpmr(PMRN_PMLCA0); | ||
| 46 | break; | ||
| 47 | case 1: | ||
| 48 | pmlca = mfpmr(PMRN_PMLCA1); | ||
| 49 | break; | ||
| 50 | case 2: | ||
| 51 | pmlca = mfpmr(PMRN_PMLCA2); | ||
| 52 | break; | ||
| 53 | case 3: | ||
| 54 | pmlca = mfpmr(PMRN_PMLCA3); | ||
| 55 | break; | ||
| 56 | default: | ||
| 57 | panic("Bad ctr number\n"); | ||
| 58 | } | ||
| 59 | |||
| 60 | return pmlca; | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline void set_pmlca(int ctr, u32 pmlca) | ||
| 64 | { | ||
| 65 | switch (ctr) { | ||
| 66 | case 0: | ||
| 67 | mtpmr(PMRN_PMLCA0, pmlca); | ||
| 68 | break; | ||
| 69 | case 1: | ||
| 70 | mtpmr(PMRN_PMLCA1, pmlca); | ||
| 71 | break; | ||
| 72 | case 2: | ||
| 73 | mtpmr(PMRN_PMLCA2, pmlca); | ||
| 74 | break; | ||
| 75 | case 3: | ||
| 76 | mtpmr(PMRN_PMLCA3, pmlca); | ||
| 77 | break; | ||
| 78 | default: | ||
| 79 | panic("Bad ctr number\n"); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | void init_pmc_stop(int ctr) | ||
| 84 | { | ||
| 85 | u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU | | ||
| 86 | PMLCA_FCM1 | PMLCA_FCM0); | ||
| 87 | u32 pmlcb = 0; | ||
| 88 | |||
| 89 | switch (ctr) { | ||
| 90 | case 0: | ||
| 91 | mtpmr(PMRN_PMLCA0, pmlca); | ||
| 92 | mtpmr(PMRN_PMLCB0, pmlcb); | ||
| 93 | break; | ||
| 94 | case 1: | ||
| 95 | mtpmr(PMRN_PMLCA1, pmlca); | ||
| 96 | mtpmr(PMRN_PMLCB1, pmlcb); | ||
| 97 | break; | ||
| 98 | case 2: | ||
| 99 | mtpmr(PMRN_PMLCA2, pmlca); | ||
| 100 | mtpmr(PMRN_PMLCB2, pmlcb); | ||
| 101 | break; | ||
| 102 | case 3: | ||
| 103 | mtpmr(PMRN_PMLCA3, pmlca); | ||
| 104 | mtpmr(PMRN_PMLCB3, pmlcb); | ||
| 105 | break; | ||
| 106 | default: | ||
| 107 | panic("Bad ctr number!\n"); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | void set_pmc_event(int ctr, int event) | ||
| 112 | { | ||
| 113 | u32 pmlca; | ||
| 114 | |||
| 115 | pmlca = get_pmlca(ctr); | ||
| 116 | |||
| 117 | pmlca = (pmlca & ~PMLCA_EVENT_MASK) | | ||
| 118 | ((event << PMLCA_EVENT_SHIFT) & | ||
| 119 | PMLCA_EVENT_MASK); | ||
| 120 | |||
| 121 | set_pmlca(ctr, pmlca); | ||
| 122 | } | ||
| 123 | |||
| 124 | void set_pmc_user_kernel(int ctr, int user, int kernel) | ||
| 125 | { | ||
| 126 | u32 pmlca; | ||
| 127 | |||
| 128 | pmlca = get_pmlca(ctr); | ||
| 129 | |||
| 130 | if(user) | ||
| 131 | pmlca &= ~PMLCA_FCU; | ||
| 132 | else | ||
| 133 | pmlca |= PMLCA_FCU; | ||
| 134 | |||
| 135 | if(kernel) | ||
| 136 | pmlca &= ~PMLCA_FCS; | ||
| 137 | else | ||
| 138 | pmlca |= PMLCA_FCS; | ||
| 139 | |||
| 140 | set_pmlca(ctr, pmlca); | ||
| 141 | } | ||
| 142 | |||
| 143 | void set_pmc_marked(int ctr, int mark0, int mark1) | ||
| 144 | { | ||
| 145 | u32 pmlca = get_pmlca(ctr); | ||
| 146 | |||
| 147 | if(mark0) | ||
| 148 | pmlca &= ~PMLCA_FCM0; | ||
| 149 | else | ||
| 150 | pmlca |= PMLCA_FCM0; | ||
| 151 | |||
| 152 | if(mark1) | ||
| 153 | pmlca &= ~PMLCA_FCM1; | ||
| 154 | else | ||
| 155 | pmlca |= PMLCA_FCM1; | ||
| 156 | |||
| 157 | set_pmlca(ctr, pmlca); | ||
| 158 | } | ||
| 159 | |||
| 160 | void pmc_start_ctr(int ctr, int enable) | ||
| 161 | { | ||
| 162 | u32 pmlca = get_pmlca(ctr); | ||
| 163 | |||
| 164 | pmlca &= ~PMLCA_FC; | ||
| 165 | |||
| 166 | if (enable) | ||
| 167 | pmlca |= PMLCA_CE; | ||
| 168 | else | ||
| 169 | pmlca &= ~PMLCA_CE; | ||
| 170 | |||
| 171 | set_pmlca(ctr, pmlca); | ||
| 172 | } | ||
| 173 | |||
| 174 | void pmc_start_ctrs(int enable) | ||
| 175 | { | ||
| 176 | u32 pmgc0 = mfpmr(PMRN_PMGC0); | ||
| 177 | |||
| 178 | pmgc0 &= ~PMGC0_FAC; | ||
| 179 | pmgc0 |= PMGC0_FCECE; | ||
| 180 | |||
| 181 | if (enable) | ||
| 182 | pmgc0 |= PMGC0_PMIE; | ||
| 183 | else | ||
| 184 | pmgc0 &= ~PMGC0_PMIE; | ||
| 185 | |||
| 186 | mtpmr(PMRN_PMGC0, pmgc0); | ||
| 187 | } | ||
| 188 | |||
| 189 | void pmc_stop_ctrs(void) | ||
| 190 | { | ||
| 191 | u32 pmgc0 = mfpmr(PMRN_PMGC0); | ||
| 192 | |||
| 193 | pmgc0 |= PMGC0_FAC; | ||
| 194 | |||
| 195 | pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE); | ||
| 196 | |||
| 197 | mtpmr(PMRN_PMGC0, pmgc0); | ||
| 198 | } | ||
| 199 | |||
| 200 | void dump_pmcs(void) | ||
| 201 | { | ||
| 202 | printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0)); | ||
| 203 | printk("pmc\t\tpmlca\t\tpmlcb\n"); | ||
| 204 | printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0), | ||
| 205 | mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0)); | ||
| 206 | printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1), | ||
| 207 | mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1)); | ||
| 208 | printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2), | ||
| 209 | mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2)); | ||
| 210 | printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3), | ||
| 211 | mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3)); | ||
| 212 | } | ||
| 213 | |||
| 214 | EXPORT_SYMBOL(init_pmc_stop); | ||
| 215 | EXPORT_SYMBOL(set_pmc_event); | ||
| 216 | EXPORT_SYMBOL(set_pmc_user_kernel); | ||
| 217 | EXPORT_SYMBOL(set_pmc_marked); | ||
| 218 | EXPORT_SYMBOL(pmc_start_ctr); | ||
| 219 | EXPORT_SYMBOL(pmc_start_ctrs); | ||
| 220 | EXPORT_SYMBOL(pmc_stop_ctrs); | ||
| 221 | EXPORT_SYMBOL(dump_pmcs); | ||
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index a0a2efadeabf..3d8f6f44641e 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c | |||
| @@ -71,7 +71,7 @@ int reserve_pmc_hardware(perf_irq_t new_perf_irq) | |||
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | pmc_owner_caller = __builtin_return_address(0); | 73 | pmc_owner_caller = __builtin_return_address(0); |
| 74 | perf_irq = new_perf_irq ? : dummy_perf; | 74 | perf_irq = new_perf_irq ? new_perf_irq : dummy_perf; |
| 75 | 75 | ||
| 76 | out: | 76 | out: |
| 77 | spin_unlock(&pmc_owner_lock); | 77 | spin_unlock(&pmc_owner_lock); |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 865b9648d0d5..bdb412d4b748 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -1014,7 +1014,7 @@ EXPORT_SYMBOL(find_all_nodes); | |||
| 1014 | /** Checks if the given "compat" string matches one of the strings in | 1014 | /** Checks if the given "compat" string matches one of the strings in |
| 1015 | * the device's "compatible" property | 1015 | * the device's "compatible" property |
| 1016 | */ | 1016 | */ |
| 1017 | int device_is_compatible(struct device_node *device, const char *compat) | 1017 | int device_is_compatible(const struct device_node *device, const char *compat) |
| 1018 | { | 1018 | { |
| 1019 | const char* cp; | 1019 | const char* cp; |
| 1020 | int cplen, l; | 1020 | int cplen, l; |
| @@ -1491,7 +1491,8 @@ static int __init prom_reconfig_setup(void) | |||
| 1491 | __initcall(prom_reconfig_setup); | 1491 | __initcall(prom_reconfig_setup); |
| 1492 | #endif | 1492 | #endif |
| 1493 | 1493 | ||
| 1494 | struct property *of_find_property(struct device_node *np, const char *name, | 1494 | struct property *of_find_property(const struct device_node *np, |
| 1495 | const char *name, | ||
| 1495 | int *lenp) | 1496 | int *lenp) |
| 1496 | { | 1497 | { |
| 1497 | struct property *pp; | 1498 | struct property *pp; |
| @@ -1512,7 +1513,8 @@ struct property *of_find_property(struct device_node *np, const char *name, | |||
| 1512 | * Find a property with a given name for a given node | 1513 | * Find a property with a given name for a given node |
| 1513 | * and return the value. | 1514 | * and return the value. |
| 1514 | */ | 1515 | */ |
| 1515 | const void *get_property(struct device_node *np, const char *name, int *lenp) | 1516 | const void *get_property(const struct device_node *np, const char *name, |
| 1517 | int *lenp) | ||
| 1516 | { | 1518 | { |
| 1517 | struct property *pp = of_find_property(np,name,lenp); | 1519 | struct property *pp = of_find_property(np,name,lenp); |
| 1518 | return pp ? pp->value : NULL; | 1520 | return pp ? pp->value : NULL; |
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 1442b63a75da..6f6fc977cb39 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
| @@ -72,6 +72,10 @@ | |||
| 72 | #define VALIDATE_BUF_SIZE 4096 | 72 | #define VALIDATE_BUF_SIZE 4096 |
| 73 | #define RTAS_MSG_MAXLEN 64 | 73 | #define RTAS_MSG_MAXLEN 64 |
| 74 | 74 | ||
| 75 | /* Quirk - RTAS requires 4k list length and block size */ | ||
| 76 | #define RTAS_BLKLIST_LENGTH 4096 | ||
| 77 | #define RTAS_BLK_SIZE 4096 | ||
| 78 | |||
| 75 | struct flash_block { | 79 | struct flash_block { |
| 76 | char *data; | 80 | char *data; |
| 77 | unsigned long length; | 81 | unsigned long length; |
| @@ -83,7 +87,7 @@ struct flash_block { | |||
| 83 | * into a version/length and translate the pointers | 87 | * into a version/length and translate the pointers |
| 84 | * to absolute. | 88 | * to absolute. |
| 85 | */ | 89 | */ |
| 86 | #define FLASH_BLOCKS_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct flash_block)) | 90 | #define FLASH_BLOCKS_PER_NODE ((RTAS_BLKLIST_LENGTH - 16) / sizeof(struct flash_block)) |
| 87 | struct flash_block_list { | 91 | struct flash_block_list { |
| 88 | unsigned long num_blocks; | 92 | unsigned long num_blocks; |
| 89 | struct flash_block_list *next; | 93 | struct flash_block_list *next; |
| @@ -96,6 +100,9 @@ struct flash_block_list_header { /* just the header of flash_block_list */ | |||
| 96 | 100 | ||
| 97 | static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; | 101 | static struct flash_block_list_header rtas_firmware_flash_list = {0, NULL}; |
| 98 | 102 | ||
| 103 | /* Use slab cache to guarantee 4k alignment */ | ||
| 104 | static kmem_cache_t *flash_block_cache = NULL; | ||
| 105 | |||
| 99 | #define FLASH_BLOCK_LIST_VERSION (1UL) | 106 | #define FLASH_BLOCK_LIST_VERSION (1UL) |
| 100 | 107 | ||
| 101 | /* Local copy of the flash block list. | 108 | /* Local copy of the flash block list. |
| @@ -153,7 +160,7 @@ static int flash_list_valid(struct flash_block_list *flist) | |||
| 153 | return FLASH_IMG_NULL_DATA; | 160 | return FLASH_IMG_NULL_DATA; |
| 154 | } | 161 | } |
| 155 | block_size = f->blocks[i].length; | 162 | block_size = f->blocks[i].length; |
| 156 | if (block_size <= 0 || block_size > PAGE_SIZE) { | 163 | if (block_size <= 0 || block_size > RTAS_BLK_SIZE) { |
| 157 | return FLASH_IMG_BAD_LEN; | 164 | return FLASH_IMG_BAD_LEN; |
| 158 | } | 165 | } |
| 159 | image_size += block_size; | 166 | image_size += block_size; |
| @@ -177,9 +184,9 @@ static void free_flash_list(struct flash_block_list *f) | |||
| 177 | 184 | ||
| 178 | while (f) { | 185 | while (f) { |
| 179 | for (i = 0; i < f->num_blocks; i++) | 186 | for (i = 0; i < f->num_blocks; i++) |
| 180 | free_page((unsigned long)(f->blocks[i].data)); | 187 | kmem_cache_free(flash_block_cache, f->blocks[i].data); |
| 181 | next = f->next; | 188 | next = f->next; |
| 182 | free_page((unsigned long)f); | 189 | kmem_cache_free(flash_block_cache, f); |
| 183 | f = next; | 190 | f = next; |
| 184 | } | 191 | } |
| 185 | } | 192 | } |
| @@ -278,6 +285,12 @@ static ssize_t rtas_flash_read(struct file *file, char __user *buf, | |||
| 278 | return msglen; | 285 | return msglen; |
| 279 | } | 286 | } |
| 280 | 287 | ||
| 288 | /* constructor for flash_block_cache */ | ||
| 289 | void rtas_block_ctor(void *ptr, kmem_cache_t *cache, unsigned long flags) | ||
| 290 | { | ||
| 291 | memset(ptr, 0, RTAS_BLK_SIZE); | ||
| 292 | } | ||
| 293 | |||
| 281 | /* We could be much more efficient here. But to keep this function | 294 | /* We could be much more efficient here. But to keep this function |
| 282 | * simple we allocate a page to the block list no matter how small the | 295 | * simple we allocate a page to the block list no matter how small the |
| 283 | * count is. If the system is low on memory it will be just as well | 296 | * count is. If the system is low on memory it will be just as well |
| @@ -302,7 +315,7 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, | |||
| 302 | * proc file | 315 | * proc file |
| 303 | */ | 316 | */ |
| 304 | if (uf->flist == NULL) { | 317 | if (uf->flist == NULL) { |
| 305 | uf->flist = (struct flash_block_list *) get_zeroed_page(GFP_KERNEL); | 318 | uf->flist = kmem_cache_alloc(flash_block_cache, GFP_KERNEL); |
| 306 | if (!uf->flist) | 319 | if (!uf->flist) |
| 307 | return -ENOMEM; | 320 | return -ENOMEM; |
| 308 | } | 321 | } |
| @@ -313,21 +326,21 @@ static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, | |||
| 313 | next_free = fl->num_blocks; | 326 | next_free = fl->num_blocks; |
| 314 | if (next_free == FLASH_BLOCKS_PER_NODE) { | 327 | if (next_free == FLASH_BLOCKS_PER_NODE) { |
| 315 | /* Need to allocate another block_list */ | 328 | /* Need to allocate another block_list */ |
| 316 | fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL); | 329 | fl->next = kmem_cache_alloc(flash_block_cache, GFP_KERNEL); |
| 317 | if (!fl->next) | 330 | if (!fl->next) |
| 318 | return -ENOMEM; | 331 | return -ENOMEM; |
| 319 | fl = fl->next; | 332 | fl = fl->next; |
| 320 | next_free = 0; | 333 | next_free = 0; |
| 321 | } | 334 | } |
| 322 | 335 | ||
| 323 | if (count > PAGE_SIZE) | 336 | if (count > RTAS_BLK_SIZE) |
| 324 | count = PAGE_SIZE; | 337 | count = RTAS_BLK_SIZE; |
| 325 | p = (char *)get_zeroed_page(GFP_KERNEL); | 338 | p = kmem_cache_alloc(flash_block_cache, GFP_KERNEL); |
| 326 | if (!p) | 339 | if (!p) |
| 327 | return -ENOMEM; | 340 | return -ENOMEM; |
| 328 | 341 | ||
| 329 | if(copy_from_user(p, buffer, count)) { | 342 | if(copy_from_user(p, buffer, count)) { |
| 330 | free_page((unsigned long)p); | 343 | kmem_cache_free(flash_block_cache, p); |
| 331 | return -EFAULT; | 344 | return -EFAULT; |
| 332 | } | 345 | } |
| 333 | fl->blocks[next_free].data = p; | 346 | fl->blocks[next_free].data = p; |
| @@ -791,6 +804,16 @@ int __init rtas_flash_init(void) | |||
| 791 | goto cleanup; | 804 | goto cleanup; |
| 792 | 805 | ||
| 793 | rtas_flash_term_hook = rtas_flash_firmware; | 806 | rtas_flash_term_hook = rtas_flash_firmware; |
| 807 | |||
| 808 | flash_block_cache = kmem_cache_create("rtas_flash_cache", | ||
| 809 | RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0, | ||
| 810 | rtas_block_ctor, NULL); | ||
| 811 | if (!flash_block_cache) { | ||
| 812 | printk(KERN_ERR "%s: failed to create block cache\n", | ||
| 813 | __FUNCTION__); | ||
| 814 | rc = -ENOMEM; | ||
| 815 | goto cleanup; | ||
| 816 | } | ||
| 794 | return 0; | 817 | return 0; |
| 795 | 818 | ||
| 796 | cleanup: | 819 | cleanup: |
| @@ -805,6 +828,10 @@ cleanup: | |||
| 805 | void __exit rtas_flash_cleanup(void) | 828 | void __exit rtas_flash_cleanup(void) |
| 806 | { | 829 | { |
| 807 | rtas_flash_term_hook = NULL; | 830 | rtas_flash_term_hook = NULL; |
| 831 | |||
| 832 | if (flash_block_cache) | ||
| 833 | kmem_cache_destroy(flash_block_cache); | ||
| 834 | |||
| 808 | remove_flash_pde(firmware_flash_pde); | 835 | remove_flash_pde(firmware_flash_pde); |
| 809 | remove_flash_pde(firmware_update_pde); | 836 | remove_flash_pde(firmware_update_pde); |
| 810 | remove_flash_pde(validate_pde); | 837 | remove_flash_pde(validate_pde); |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 191d0ab09222..a4c2964a3ca6 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
| @@ -91,6 +91,7 @@ int ucache_bsize; | |||
| 91 | unsigned long __init early_init(unsigned long dt_ptr) | 91 | unsigned long __init early_init(unsigned long dt_ptr) |
| 92 | { | 92 | { |
| 93 | unsigned long offset = reloc_offset(); | 93 | unsigned long offset = reloc_offset(); |
| 94 | struct cpu_spec *spec; | ||
| 94 | 95 | ||
| 95 | /* First zero the BSS -- use memset_io, some platforms don't have | 96 | /* First zero the BSS -- use memset_io, some platforms don't have |
| 96 | * caches on yet */ | 97 | * caches on yet */ |
| @@ -100,8 +101,11 @@ unsigned long __init early_init(unsigned long dt_ptr) | |||
| 100 | * Identify the CPU type and fix up code sections | 101 | * Identify the CPU type and fix up code sections |
| 101 | * that depend on which cpu we have. | 102 | * that depend on which cpu we have. |
| 102 | */ | 103 | */ |
| 103 | identify_cpu(offset, 0); | 104 | spec = identify_cpu(offset); |
| 104 | do_cpu_ftr_fixups(offset); | 105 | |
| 106 | do_feature_fixups(spec->cpu_features, | ||
| 107 | PTRRELOC(&__start___ftr_fixup), | ||
| 108 | PTRRELOC(&__stop___ftr_fixup)); | ||
| 105 | 109 | ||
| 106 | return KERNELBASE + offset; | 110 | return KERNELBASE + offset; |
| 107 | } | 111 | } |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 4b2e32eab9dc..16278968dab6 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
| @@ -170,6 +170,9 @@ void __init setup_paca(int cpu) | |||
| 170 | 170 | ||
| 171 | void __init early_setup(unsigned long dt_ptr) | 171 | void __init early_setup(unsigned long dt_ptr) |
| 172 | { | 172 | { |
| 173 | /* Identify CPU type */ | ||
| 174 | identify_cpu(0); | ||
| 175 | |||
| 173 | /* Assume we're on cpu 0 for now. Don't write to the paca yet! */ | 176 | /* Assume we're on cpu 0 for now. Don't write to the paca yet! */ |
| 174 | setup_paca(0); | 177 | setup_paca(0); |
| 175 | 178 | ||
| @@ -348,6 +351,14 @@ void __init setup_system(void) | |||
| 348 | { | 351 | { |
| 349 | DBG(" -> setup_system()\n"); | 352 | DBG(" -> setup_system()\n"); |
| 350 | 353 | ||
| 354 | /* Apply the CPUs-specific and firmware specific fixups to kernel | ||
| 355 | * text (nop out sections not relevant to this CPU or this firmware) | ||
| 356 | */ | ||
| 357 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
| 358 | &__start___ftr_fixup, &__stop___ftr_fixup); | ||
| 359 | do_feature_fixups(powerpc_firmware_features, | ||
| 360 | &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); | ||
| 361 | |||
| 351 | /* | 362 | /* |
| 352 | * Unflatten the device-tree passed by prom_init or kexec | 363 | * Unflatten the device-tree passed by prom_init or kexec |
| 353 | */ | 364 | */ |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 5b59bc18dfe7..a1b5e4b16151 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
| @@ -220,11 +220,8 @@ static void account_process_time(struct pt_regs *regs) | |||
| 220 | */ | 220 | */ |
| 221 | struct cpu_purr_data { | 221 | struct cpu_purr_data { |
| 222 | int initialized; /* thread is running */ | 222 | int initialized; /* thread is running */ |
| 223 | u64 tb0; /* timebase at origin time */ | ||
| 224 | u64 purr0; /* PURR at origin time */ | ||
| 225 | u64 tb; /* last TB value read */ | 223 | u64 tb; /* last TB value read */ |
| 226 | u64 purr; /* last PURR value read */ | 224 | u64 purr; /* last PURR value read */ |
| 227 | u64 stolen; /* stolen time so far */ | ||
| 228 | spinlock_t lock; | 225 | spinlock_t lock; |
| 229 | }; | 226 | }; |
| 230 | 227 | ||
| @@ -234,10 +231,8 @@ static void snapshot_tb_and_purr(void *data) | |||
| 234 | { | 231 | { |
| 235 | struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); | 232 | struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); |
| 236 | 233 | ||
| 237 | p->tb0 = mftb(); | 234 | p->tb = mftb(); |
| 238 | p->purr0 = mfspr(SPRN_PURR); | 235 | p->purr = mfspr(SPRN_PURR); |
| 239 | p->tb = p->tb0; | ||
| 240 | p->purr = 0; | ||
| 241 | wmb(); | 236 | wmb(); |
| 242 | p->initialized = 1; | 237 | p->initialized = 1; |
| 243 | } | 238 | } |
| @@ -258,37 +253,24 @@ void snapshot_timebases(void) | |||
| 258 | 253 | ||
| 259 | void calculate_steal_time(void) | 254 | void calculate_steal_time(void) |
| 260 | { | 255 | { |
| 261 | u64 tb, purr, t0; | 256 | u64 tb, purr; |
| 262 | s64 stolen; | 257 | s64 stolen; |
| 263 | struct cpu_purr_data *p0, *pme, *phim; | 258 | struct cpu_purr_data *pme; |
| 264 | int cpu; | ||
| 265 | 259 | ||
| 266 | if (!cpu_has_feature(CPU_FTR_PURR)) | 260 | if (!cpu_has_feature(CPU_FTR_PURR)) |
| 267 | return; | 261 | return; |
| 268 | cpu = smp_processor_id(); | 262 | pme = &per_cpu(cpu_purr_data, smp_processor_id()); |
| 269 | pme = &per_cpu(cpu_purr_data, cpu); | ||
| 270 | if (!pme->initialized) | 263 | if (!pme->initialized) |
| 271 | return; /* this can happen in early boot */ | 264 | return; /* this can happen in early boot */ |
| 272 | p0 = &per_cpu(cpu_purr_data, cpu & ~1); | 265 | spin_lock(&pme->lock); |
| 273 | phim = &per_cpu(cpu_purr_data, cpu ^ 1); | ||
| 274 | spin_lock(&p0->lock); | ||
| 275 | tb = mftb(); | 266 | tb = mftb(); |
| 276 | purr = mfspr(SPRN_PURR) - pme->purr0; | 267 | purr = mfspr(SPRN_PURR); |
| 277 | if (!phim->initialized || !cpu_online(cpu ^ 1)) { | 268 | stolen = (tb - pme->tb) - (purr - pme->purr); |
| 278 | stolen = (tb - pme->tb) - (purr - pme->purr); | 269 | if (stolen > 0) |
| 279 | } else { | ||
| 280 | t0 = pme->tb0; | ||
| 281 | if (phim->tb0 < t0) | ||
| 282 | t0 = phim->tb0; | ||
| 283 | stolen = phim->tb - t0 - phim->purr - purr - p0->stolen; | ||
| 284 | } | ||
| 285 | if (stolen > 0) { | ||
| 286 | account_steal_time(current, stolen); | 270 | account_steal_time(current, stolen); |
| 287 | p0->stolen += stolen; | ||
| 288 | } | ||
| 289 | pme->tb = tb; | 271 | pme->tb = tb; |
| 290 | pme->purr = purr; | 272 | pme->purr = purr; |
| 291 | spin_unlock(&p0->lock); | 273 | spin_unlock(&pme->lock); |
| 292 | } | 274 | } |
| 293 | 275 | ||
| 294 | /* | 276 | /* |
| @@ -297,30 +279,17 @@ void calculate_steal_time(void) | |||
| 297 | */ | 279 | */ |
| 298 | static void snapshot_purr(void) | 280 | static void snapshot_purr(void) |
| 299 | { | 281 | { |
| 300 | int cpu; | 282 | struct cpu_purr_data *pme; |
| 301 | u64 purr; | ||
| 302 | struct cpu_purr_data *p0, *pme, *phim; | ||
| 303 | unsigned long flags; | 283 | unsigned long flags; |
| 304 | 284 | ||
| 305 | if (!cpu_has_feature(CPU_FTR_PURR)) | 285 | if (!cpu_has_feature(CPU_FTR_PURR)) |
| 306 | return; | 286 | return; |
| 307 | cpu = smp_processor_id(); | 287 | pme = &per_cpu(cpu_purr_data, smp_processor_id()); |
| 308 | pme = &per_cpu(cpu_purr_data, cpu); | 288 | spin_lock_irqsave(&pme->lock, flags); |
| 309 | p0 = &per_cpu(cpu_purr_data, cpu & ~1); | 289 | pme->tb = mftb(); |
| 310 | phim = &per_cpu(cpu_purr_data, cpu ^ 1); | 290 | pme->purr = mfspr(SPRN_PURR); |
| 311 | spin_lock_irqsave(&p0->lock, flags); | ||
| 312 | pme->tb = pme->tb0 = mftb(); | ||
| 313 | purr = mfspr(SPRN_PURR); | ||
| 314 | if (!phim->initialized) { | ||
| 315 | pme->purr = 0; | ||
| 316 | pme->purr0 = purr; | ||
| 317 | } else { | ||
| 318 | /* set p->purr and p->purr0 for no change in p0->stolen */ | ||
| 319 | pme->purr = phim->tb - phim->tb0 - phim->purr - p0->stolen; | ||
| 320 | pme->purr0 = purr - pme->purr; | ||
| 321 | } | ||
| 322 | pme->initialized = 1; | 291 | pme->initialized = 1; |
| 323 | spin_unlock_irqrestore(&p0->lock, flags); | 292 | spin_unlock_irqrestore(&pme->lock, flags); |
| 324 | } | 293 | } |
| 325 | 294 | ||
| 326 | #endif /* CONFIG_PPC_SPLPAR */ | 295 | #endif /* CONFIG_PPC_SPLPAR */ |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ed4c2ceb5ca..c66b4771ef44 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
| @@ -843,7 +843,7 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
| 843 | 843 | ||
| 844 | void alignment_exception(struct pt_regs *regs) | 844 | void alignment_exception(struct pt_regs *regs) |
| 845 | { | 845 | { |
| 846 | int fixed = 0; | 846 | int sig, code, fixed = 0; |
| 847 | 847 | ||
| 848 | /* we don't implement logging of alignment exceptions */ | 848 | /* we don't implement logging of alignment exceptions */ |
| 849 | if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) | 849 | if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) |
| @@ -857,14 +857,16 @@ void alignment_exception(struct pt_regs *regs) | |||
| 857 | 857 | ||
| 858 | /* Operand address was bad */ | 858 | /* Operand address was bad */ |
| 859 | if (fixed == -EFAULT) { | 859 | if (fixed == -EFAULT) { |
| 860 | if (user_mode(regs)) | 860 | sig = SIGSEGV; |
| 861 | _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); | 861 | code = SEGV_ACCERR; |
| 862 | else | 862 | } else { |
| 863 | /* Search exception table */ | 863 | sig = SIGBUS; |
| 864 | bad_page_fault(regs, regs->dar, SIGSEGV); | 864 | code = BUS_ADRALN; |
| 865 | return; | ||
| 866 | } | 865 | } |
| 867 | _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); | 866 | if (user_mode(regs)) |
| 867 | _exception(sig, regs, code, regs->dar); | ||
| 868 | else | ||
| 869 | bad_page_fault(regs, regs->dar, sig); | ||
| 868 | } | 870 | } |
| 869 | 871 | ||
| 870 | void StackOverflow(struct pt_regs *regs) | 872 | void StackOverflow(struct pt_regs *regs) |
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 1a7e19cdab39..c913ad5cad29 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c | |||
| @@ -36,6 +36,8 @@ | |||
| 36 | #include <asm/vdso.h> | 36 | #include <asm/vdso.h> |
| 37 | #include <asm/vdso_datapage.h> | 37 | #include <asm/vdso_datapage.h> |
| 38 | 38 | ||
| 39 | #include "setup.h" | ||
| 40 | |||
| 39 | #undef DEBUG | 41 | #undef DEBUG |
| 40 | 42 | ||
| 41 | #ifdef DEBUG | 43 | #ifdef DEBUG |
| @@ -586,6 +588,43 @@ static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32, | |||
| 586 | return 0; | 588 | return 0; |
| 587 | } | 589 | } |
| 588 | 590 | ||
| 591 | |||
| 592 | static __init int vdso_fixup_features(struct lib32_elfinfo *v32, | ||
| 593 | struct lib64_elfinfo *v64) | ||
| 594 | { | ||
| 595 | void *start32; | ||
| 596 | unsigned long size32; | ||
| 597 | |||
| 598 | #ifdef CONFIG_PPC64 | ||
| 599 | void *start64; | ||
| 600 | unsigned long size64; | ||
| 601 | |||
| 602 | start64 = find_section64(v64->hdr, "__ftr_fixup", &size64); | ||
| 603 | if (start64) | ||
| 604 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
| 605 | start64, start64 + size64); | ||
| 606 | |||
| 607 | start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64); | ||
| 608 | if (start64) | ||
| 609 | do_feature_fixups(powerpc_firmware_features, | ||
| 610 | start64, start64 + size64); | ||
| 611 | #endif /* CONFIG_PPC64 */ | ||
| 612 | |||
| 613 | start32 = find_section32(v32->hdr, "__ftr_fixup", &size32); | ||
| 614 | if (start32) | ||
| 615 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
| 616 | start32, start32 + size32); | ||
| 617 | |||
| 618 | #ifdef CONFIG_PPC64 | ||
| 619 | start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32); | ||
| 620 | if (start32) | ||
| 621 | do_feature_fixups(powerpc_firmware_features, | ||
| 622 | start32, start32 + size32); | ||
| 623 | #endif /* CONFIG_PPC64 */ | ||
| 624 | |||
| 625 | return 0; | ||
| 626 | } | ||
| 627 | |||
| 589 | static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32, | 628 | static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32, |
| 590 | struct lib64_elfinfo *v64) | 629 | struct lib64_elfinfo *v64) |
| 591 | { | 630 | { |
| @@ -634,6 +673,9 @@ static __init int vdso_setup(void) | |||
| 634 | if (vdso_fixup_datapage(&v32, &v64)) | 673 | if (vdso_fixup_datapage(&v32, &v64)) |
| 635 | return -1; | 674 | return -1; |
| 636 | 675 | ||
| 676 | if (vdso_fixup_features(&v32, &v64)) | ||
| 677 | return -1; | ||
| 678 | |||
| 637 | if (vdso_fixup_alt_funcs(&v32, &v64)) | 679 | if (vdso_fixup_alt_funcs(&v32, &v64)) |
| 638 | return -1; | 680 | return -1; |
| 639 | 681 | ||
| @@ -714,6 +756,7 @@ void __init vdso_init(void) | |||
| 714 | * Setup the syscall map in the vDOS | 756 | * Setup the syscall map in the vDOS |
| 715 | */ | 757 | */ |
| 716 | vdso_setup_syscall_map(); | 758 | vdso_setup_syscall_map(); |
| 759 | |||
| 717 | /* | 760 | /* |
| 718 | * Initialize the vDSO images in memory, that is do necessary | 761 | * Initialize the vDSO images in memory, that is do necessary |
| 719 | * fixups of vDSO symbols, locate trampolines, etc... | 762 | * fixups of vDSO symbols, locate trampolines, etc... |
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S index 6187af2d54c3..26e138c4ce17 100644 --- a/arch/powerpc/kernel/vdso32/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S | |||
| @@ -32,6 +32,18 @@ SECTIONS | |||
| 32 | PROVIDE (_etext = .); | 32 | PROVIDE (_etext = .); |
| 33 | PROVIDE (etext = .); | 33 | PROVIDE (etext = .); |
| 34 | 34 | ||
| 35 | . = ALIGN(8); | ||
| 36 | __ftr_fixup : { | ||
| 37 | *(__ftr_fixup) | ||
| 38 | } | ||
| 39 | |||
| 40 | #ifdef CONFIG_PPC64 | ||
| 41 | . = ALIGN(8); | ||
| 42 | __fw_ftr_fixup : { | ||
| 43 | *(__fw_ftr_fixup) | ||
| 44 | } | ||
| 45 | #endif | ||
| 46 | |||
| 35 | /* Other stuff is appended to the text segment: */ | 47 | /* Other stuff is appended to the text segment: */ |
| 36 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } | 48 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } |
| 37 | .rodata1 : { *(.rodata1) } | 49 | .rodata1 : { *(.rodata1) } |
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S index 56e76ff5498f..40ffd9b6cef7 100644 --- a/arch/powerpc/kernel/vdso64/gettimeofday.S +++ b/arch/powerpc/kernel/vdso64/gettimeofday.S | |||
| @@ -229,8 +229,10 @@ V_FUNCTION_BEGIN(__do_get_xsec) | |||
| 229 | xor r0,r8,r8 /* create dependency */ | 229 | xor r0,r8,r8 /* create dependency */ |
| 230 | add r3,r3,r0 | 230 | add r3,r3,r0 |
| 231 | 231 | ||
| 232 | /* Get TB & offset it */ | 232 | /* Get TB & offset it. We use the MFTB macro which will generate |
| 233 | mftb r7 | 233 | * workaround code for Cell. |
| 234 | */ | ||
| 235 | MFTB(r7) | ||
| 234 | ld r9,CFG_TB_ORIG_STAMP(r3) | 236 | ld r9,CFG_TB_ORIG_STAMP(r3) |
| 235 | subf r7,r9,r7 | 237 | subf r7,r9,r7 |
| 236 | 238 | ||
diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S index 4a2b6dc0960c..2d70f35d50b5 100644 --- a/arch/powerpc/kernel/vdso64/vdso64.lds.S +++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S | |||
| @@ -31,6 +31,16 @@ SECTIONS | |||
| 31 | PROVIDE (_etext = .); | 31 | PROVIDE (_etext = .); |
| 32 | PROVIDE (etext = .); | 32 | PROVIDE (etext = .); |
| 33 | 33 | ||
| 34 | . = ALIGN(8); | ||
| 35 | __ftr_fixup : { | ||
| 36 | *(__ftr_fixup) | ||
| 37 | } | ||
| 38 | |||
| 39 | . = ALIGN(8); | ||
| 40 | __fw_ftr_fixup : { | ||
| 41 | *(__fw_ftr_fixup) | ||
| 42 | } | ||
| 43 | |||
| 34 | /* Other stuff is appended to the text segment: */ | 44 | /* Other stuff is appended to the text segment: */ |
| 35 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } | 45 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } |
| 36 | .rodata1 : { *(.rodata1) } | 46 | .rodata1 : { *(.rodata1) } |
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index cb87e71eec66..ed007878d1bf 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
| @@ -92,9 +92,9 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | |||
| 92 | &tbl->it_index, &offset, &size); | 92 | &tbl->it_index, &offset, &size); |
| 93 | 93 | ||
| 94 | /* TCE table size - measured in tce entries */ | 94 | /* TCE table size - measured in tce entries */ |
| 95 | tbl->it_size = size >> PAGE_SHIFT; | 95 | tbl->it_size = size >> IOMMU_PAGE_SHIFT; |
| 96 | /* offset for VIO should always be 0 */ | 96 | /* offset for VIO should always be 0 */ |
| 97 | tbl->it_offset = offset >> PAGE_SHIFT; | 97 | tbl->it_offset = offset >> IOMMU_PAGE_SHIFT; |
| 98 | tbl->it_busno = 0; | 98 | tbl->it_busno = 0; |
| 99 | tbl->it_type = TCE_VB; | 99 | tbl->it_type = TCE_VB; |
| 100 | 100 | ||
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index cb0e8d46c3e8..e8342d867536 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
| @@ -108,13 +108,7 @@ SECTIONS | |||
| 108 | 108 | ||
| 109 | .initcall.init : { | 109 | .initcall.init : { |
| 110 | __initcall_start = .; | 110 | __initcall_start = .; |
| 111 | *(.initcall1.init) | 111 | INITCALLS |
| 112 | *(.initcall2.init) | ||
| 113 | *(.initcall3.init) | ||
| 114 | *(.initcall4.init) | ||
| 115 | *(.initcall5.init) | ||
| 116 | *(.initcall6.init) | ||
| 117 | *(.initcall7.init) | ||
| 118 | __initcall_end = .; | 112 | __initcall_end = .; |
| 119 | } | 113 | } |
| 120 | 114 | ||
