diff options
Diffstat (limited to 'arch/powerpc/kernel')
54 files changed, 2119 insertions, 1936 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 8b133afbdc20..d2ded19e4064 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -17,11 +17,11 @@ obj-y += vdso32/ | |||
17 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ | 17 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ |
18 | signal_64.o ptrace32.o \ | 18 | signal_64.o ptrace32.o \ |
19 | paca.o cpu_setup_ppc970.o \ | 19 | paca.o cpu_setup_ppc970.o \ |
20 | firmware.o sysfs.o | 20 | firmware.o sysfs.o nvram_64.o |
21 | obj-$(CONFIG_PPC64) += vdso64/ | 21 | obj-$(CONFIG_PPC64) += vdso64/ |
22 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o | 22 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o |
23 | obj-$(CONFIG_PPC_970_NAP) += idle_power4.o | 23 | obj-$(CONFIG_PPC_970_NAP) += idle_power4.o |
24 | obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o | 24 | obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o |
25 | procfs-$(CONFIG_PPC64) := proc_ppc64.o | 25 | procfs-$(CONFIG_PPC64) := proc_ppc64.o |
26 | obj-$(CONFIG_PROC_FS) += $(procfs-y) | 26 | obj-$(CONFIG_PROC_FS) += $(procfs-y) |
27 | rtaspci-$(CONFIG_PPC64) := rtas_pci.o | 27 | rtaspci-$(CONFIG_PPC64) := rtas_pci.o |
@@ -32,13 +32,11 @@ obj-$(CONFIG_LPARCFG) += lparcfg.o | |||
32 | obj-$(CONFIG_IBMVIO) += vio.o | 32 | obj-$(CONFIG_IBMVIO) += vio.o |
33 | obj-$(CONFIG_IBMEBUS) += ibmebus.o | 33 | obj-$(CONFIG_IBMEBUS) += ibmebus.o |
34 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o | 34 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
35 | obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o | ||
36 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 35 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
37 | obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o | 36 | obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o |
38 | obj-$(CONFIG_TAU) += tau_6xx.o | 37 | obj-$(CONFIG_TAU) += tau_6xx.o |
39 | obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o | 38 | obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o |
40 | obj32-$(CONFIG_MODULES) += module_32.o | 39 | obj32-$(CONFIG_MODULES) += module_32.o |
41 | obj-$(CONFIG_E500) += perfmon_fsl_booke.o | ||
42 | 40 | ||
43 | ifeq ($(CONFIG_PPC_MERGE),y) | 41 | ifeq ($(CONFIG_PPC_MERGE),y) |
44 | 42 | ||
@@ -60,11 +58,11 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o | |||
60 | obj-$(CONFIG_SMP) += smp.o | 58 | obj-$(CONFIG_SMP) += smp.o |
61 | obj-$(CONFIG_KPROBES) += kprobes.o | 59 | obj-$(CONFIG_KPROBES) += kprobes.o |
62 | obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o | 60 | obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o |
61 | |||
63 | module-$(CONFIG_PPC64) += module_64.o | 62 | module-$(CONFIG_PPC64) += module_64.o |
64 | obj-$(CONFIG_MODULES) += $(module-y) | 63 | obj-$(CONFIG_MODULES) += $(module-y) |
65 | 64 | ||
66 | pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \ | 65 | pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o |
67 | pci_direct_iommu.o iomap.o | ||
68 | pci32-$(CONFIG_PPC32) := pci_32.o | 66 | pci32-$(CONFIG_PPC32) := pci_32.o |
69 | obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) | 67 | obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) |
70 | kexec-$(CONFIG_PPC64) := machine_kexec_64.o | 68 | kexec-$(CONFIG_PPC64) := machine_kexec_64.o |
@@ -73,8 +71,13 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) | |||
73 | obj-$(CONFIG_AUDIT) += audit.o | 71 | obj-$(CONFIG_AUDIT) += audit.o |
74 | obj64-$(CONFIG_AUDIT) += compat_audit.o | 72 | obj64-$(CONFIG_AUDIT) += compat_audit.o |
75 | 73 | ||
74 | ifneq ($(CONFIG_PPC_INDIRECT_IO),y) | ||
75 | obj-y += iomap.o | ||
76 | endif | ||
77 | |||
76 | ifeq ($(CONFIG_PPC_ISERIES),y) | 78 | ifeq ($(CONFIG_PPC_ISERIES),y) |
77 | $(obj)/head_64.o: $(obj)/lparmap.s | 79 | extra-y += lparmap.s |
80 | $(obj)/head_64.o: $(obj)/lparmap.s | ||
78 | AFLAGS_head_64.o += -I$(obj) | 81 | AFLAGS_head_64.o += -I$(obj) |
79 | endif | 82 | endif |
80 | 83 | ||
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index d06f378597bb..e96521530d21 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -118,7 +118,8 @@ int main(void) | |||
118 | DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); | 118 | DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); |
119 | DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); | 119 | DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); |
120 | DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); | 120 | DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); |
121 | DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); | 121 | DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled)); |
122 | DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled)); | ||
122 | DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); | 123 | DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); |
123 | DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); | 124 | DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); |
124 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); | 125 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); |
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/cpu_setup_ppc970.S b/arch/powerpc/kernel/cpu_setup_ppc970.S index 652594891d58..bf118c385752 100644 --- a/arch/powerpc/kernel/cpu_setup_ppc970.S +++ b/arch/powerpc/kernel/cpu_setup_ppc970.S | |||
@@ -83,6 +83,22 @@ _GLOBAL(__setup_cpu_ppc970) | |||
83 | rldimi r0,r11,52,8 /* set NAP and DPM */ | 83 | rldimi r0,r11,52,8 /* set NAP and DPM */ |
84 | li r11,0 | 84 | li r11,0 |
85 | rldimi r0,r11,32,31 /* clear EN_ATTN */ | 85 | rldimi r0,r11,32,31 /* clear EN_ATTN */ |
86 | b load_hids /* Jump to shared code */ | ||
87 | |||
88 | |||
89 | _GLOBAL(__setup_cpu_ppc970MP) | ||
90 | /* Do nothing if not running in HV mode */ | ||
91 | mfmsr r0 | ||
92 | rldicl. r0,r0,4,63 | ||
93 | beqlr | ||
94 | |||
95 | mfspr r0,SPRN_HID0 | ||
96 | li r11,0x15 /* clear DOZE and SLEEP */ | ||
97 | rldimi r0,r11,52,6 /* set DEEPNAP, NAP and DPM */ | ||
98 | li r11,0 | ||
99 | rldimi r0,r11,32,31 /* clear EN_ATTN */ | ||
100 | |||
101 | load_hids: | ||
86 | mtspr SPRN_HID0,r0 | 102 | mtspr SPRN_HID0,r0 |
87 | mfspr r0,SPRN_HID0 | 103 | mfspr r0,SPRN_HID0 |
88 | mfspr r0,SPRN_HID0 | 104 | mfspr r0,SPRN_HID0 |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 47a613cdd775..b742013bb9da 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); |
@@ -41,6 +42,7 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); | |||
41 | #endif /* CONFIG_PPC32 */ | 42 | #endif /* CONFIG_PPC32 */ |
42 | #ifdef CONFIG_PPC64 | 43 | #ifdef CONFIG_PPC64 |
43 | extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); | 44 | extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); |
45 | extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec); | ||
44 | extern void __restore_cpu_ppc970(void); | 46 | extern void __restore_cpu_ppc970(void); |
45 | #endif /* CONFIG_PPC64 */ | 47 | #endif /* CONFIG_PPC64 */ |
46 | 48 | ||
@@ -73,7 +75,7 @@ extern void __restore_cpu_ppc970(void); | |||
73 | #define PPC_FEATURE_SPE_COMP 0 | 75 | #define PPC_FEATURE_SPE_COMP 0 |
74 | #endif | 76 | #endif |
75 | 77 | ||
76 | struct cpu_spec cpu_specs[] = { | 78 | static struct cpu_spec cpu_specs[] = { |
77 | #ifdef CONFIG_PPC64 | 79 | #ifdef CONFIG_PPC64 |
78 | { /* Power3 */ | 80 | { /* Power3 */ |
79 | .pvr_mask = 0xffff0000, | 81 | .pvr_mask = 0xffff0000, |
@@ -221,8 +223,23 @@ struct cpu_spec cpu_specs[] = { | |||
221 | .icache_bsize = 128, | 223 | .icache_bsize = 128, |
222 | .dcache_bsize = 128, | 224 | .dcache_bsize = 128, |
223 | .num_pmcs = 8, | 225 | .num_pmcs = 8, |
224 | .cpu_setup = __setup_cpu_ppc970, | 226 | .cpu_setup = __setup_cpu_ppc970MP, |
225 | .cpu_restore = __restore_cpu_ppc970, | 227 | .cpu_restore = __restore_cpu_ppc970, |
228 | .oprofile_cpu_type = "ppc64/970MP", | ||
229 | .oprofile_type = PPC_OPROFILE_POWER4, | ||
230 | .platform = "ppc970", | ||
231 | }, | ||
232 | { /* PPC970GX */ | ||
233 | .pvr_mask = 0xffff0000, | ||
234 | .pvr_value = 0x00450000, | ||
235 | .cpu_name = "PPC970GX", | ||
236 | .cpu_features = CPU_FTRS_PPC970, | ||
237 | .cpu_user_features = COMMON_USER_POWER4 | | ||
238 | PPC_FEATURE_HAS_ALTIVEC_COMP, | ||
239 | .icache_bsize = 128, | ||
240 | .dcache_bsize = 128, | ||
241 | .num_pmcs = 8, | ||
242 | .cpu_setup = __setup_cpu_ppc970, | ||
226 | .oprofile_cpu_type = "ppc64/970", | 243 | .oprofile_cpu_type = "ppc64/970", |
227 | .oprofile_type = PPC_OPROFILE_POWER4, | 244 | .oprofile_type = PPC_OPROFILE_POWER4, |
228 | .platform = "ppc970", | 245 | .platform = "ppc970", |
@@ -260,15 +277,50 @@ struct cpu_spec cpu_specs[] = { | |||
260 | .oprofile_mmcra_sipr = MMCRA_SIPR, | 277 | .oprofile_mmcra_sipr = MMCRA_SIPR, |
261 | .platform = "power5+", | 278 | .platform = "power5+", |
262 | }, | 279 | }, |
280 | { /* POWER6 in P5+ mode; 2.04-compliant processor */ | ||
281 | .pvr_mask = 0xffffffff, | ||
282 | .pvr_value = 0x0f000001, | ||
283 | .cpu_name = "POWER5+", | ||
284 | .cpu_features = CPU_FTRS_POWER5, | ||
285 | .cpu_user_features = COMMON_USER_POWER5_PLUS, | ||
286 | .icache_bsize = 128, | ||
287 | .dcache_bsize = 128, | ||
288 | .num_pmcs = 6, | ||
289 | .oprofile_cpu_type = "ppc64/power6", | ||
290 | .oprofile_type = PPC_OPROFILE_POWER4, | ||
291 | .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, | ||
292 | .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR, | ||
293 | .oprofile_mmcra_clear = POWER6_MMCRA_THRM | | ||
294 | POWER6_MMCRA_OTHER, | ||
295 | .platform = "power5+", | ||
296 | }, | ||
263 | { /* Power6 */ | 297 | { /* Power6 */ |
264 | .pvr_mask = 0xffff0000, | 298 | .pvr_mask = 0xffff0000, |
265 | .pvr_value = 0x003e0000, | 299 | .pvr_value = 0x003e0000, |
266 | .cpu_name = "POWER6", | 300 | .cpu_name = "POWER6 (raw)", |
301 | .cpu_features = CPU_FTRS_POWER6, | ||
302 | .cpu_user_features = COMMON_USER_POWER6 | | ||
303 | PPC_FEATURE_POWER6_EXT, | ||
304 | .icache_bsize = 128, | ||
305 | .dcache_bsize = 128, | ||
306 | .num_pmcs = 6, | ||
307 | .oprofile_cpu_type = "ppc64/power6", | ||
308 | .oprofile_type = PPC_OPROFILE_POWER4, | ||
309 | .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, | ||
310 | .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR, | ||
311 | .oprofile_mmcra_clear = POWER6_MMCRA_THRM | | ||
312 | POWER6_MMCRA_OTHER, | ||
313 | .platform = "power6x", | ||
314 | }, | ||
315 | { /* 2.05-compliant processor, i.e. Power6 "architected" mode */ | ||
316 | .pvr_mask = 0xffffffff, | ||
317 | .pvr_value = 0x0f000002, | ||
318 | .cpu_name = "POWER6 (architected)", | ||
267 | .cpu_features = CPU_FTRS_POWER6, | 319 | .cpu_features = CPU_FTRS_POWER6, |
268 | .cpu_user_features = COMMON_USER_POWER6, | 320 | .cpu_user_features = COMMON_USER_POWER6, |
269 | .icache_bsize = 128, | 321 | .icache_bsize = 128, |
270 | .dcache_bsize = 128, | 322 | .dcache_bsize = 128, |
271 | .num_pmcs = 8, | 323 | .num_pmcs = 6, |
272 | .oprofile_cpu_type = "ppc64/power6", | 324 | .oprofile_cpu_type = "ppc64/power6", |
273 | .oprofile_type = PPC_OPROFILE_POWER4, | 325 | .oprofile_type = PPC_OPROFILE_POWER4, |
274 | .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, | 326 | .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, |
@@ -287,6 +339,9 @@ struct cpu_spec cpu_specs[] = { | |||
287 | PPC_FEATURE_SMT, | 339 | PPC_FEATURE_SMT, |
288 | .icache_bsize = 128, | 340 | .icache_bsize = 128, |
289 | .dcache_bsize = 128, | 341 | .dcache_bsize = 128, |
342 | .num_pmcs = 4, | ||
343 | .oprofile_cpu_type = "ppc64/cell-be", | ||
344 | .oprofile_type = PPC_OPROFILE_CELL, | ||
290 | .platform = "ppc-cell-be", | 345 | .platform = "ppc-cell-be", |
291 | }, | 346 | }, |
292 | { /* PA Semi PA6T */ | 347 | { /* PA Semi PA6T */ |
@@ -778,13 +833,24 @@ struct cpu_spec cpu_specs[] = { | |||
778 | .pvr_mask = 0x7fff0000, | 833 | .pvr_mask = 0x7fff0000, |
779 | .pvr_value = 0x00840000, | 834 | .pvr_value = 0x00840000, |
780 | .cpu_name = "e300c2", | 835 | .cpu_name = "e300c2", |
781 | .cpu_features = CPU_FTRS_E300, | 836 | .cpu_features = CPU_FTRS_E300C2, |
782 | .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, | 837 | .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, |
783 | .icache_bsize = 32, | 838 | .icache_bsize = 32, |
784 | .dcache_bsize = 32, | 839 | .dcache_bsize = 32, |
785 | .cpu_setup = __setup_cpu_603, | 840 | .cpu_setup = __setup_cpu_603, |
786 | .platform = "ppc603", | 841 | .platform = "ppc603", |
787 | }, | 842 | }, |
843 | { /* e300c3 on 83xx */ | ||
844 | .pvr_mask = 0x7fff0000, | ||
845 | .pvr_value = 0x00850000, | ||
846 | .cpu_name = "e300c3", | ||
847 | .cpu_features = CPU_FTRS_E300, | ||
848 | .cpu_user_features = COMMON_USER, | ||
849 | .icache_bsize = 32, | ||
850 | .dcache_bsize = 32, | ||
851 | .cpu_setup = __setup_cpu_603, | ||
852 | .platform = "ppc603", | ||
853 | }, | ||
788 | { /* default match, we assume split I/D cache & TB (non-601)... */ | 854 | { /* default match, we assume split I/D cache & TB (non-601)... */ |
789 | .pvr_mask = 0x00000000, | 855 | .pvr_mask = 0x00000000, |
790 | .pvr_value = 0x00000000, | 856 | .pvr_value = 0x00000000, |
@@ -1070,8 +1136,7 @@ struct cpu_spec cpu_specs[] = { | |||
1070 | .pvr_mask = 0xff000fff, | 1136 | .pvr_mask = 0xff000fff, |
1071 | .pvr_value = 0x53000890, | 1137 | .pvr_value = 0x53000890, |
1072 | .cpu_name = "440SPe Rev. A", | 1138 | .cpu_name = "440SPe Rev. A", |
1073 | .cpu_features = CPU_FTR_SPLIT_ID_CACHE | | 1139 | .cpu_features = CPU_FTRS_44X, |
1074 | CPU_FTR_USE_TB, | ||
1075 | .cpu_user_features = COMMON_USER_BOOKE, | 1140 | .cpu_user_features = COMMON_USER_BOOKE, |
1076 | .icache_bsize = 32, | 1141 | .icache_bsize = 32, |
1077 | .dcache_bsize = 32, | 1142 | .dcache_bsize = 32, |
@@ -1152,3 +1217,67 @@ struct cpu_spec cpu_specs[] = { | |||
1152 | #endif /* !CLASSIC_PPC */ | 1217 | #endif /* !CLASSIC_PPC */ |
1153 | #endif /* CONFIG_PPC32 */ | 1218 | #endif /* CONFIG_PPC32 */ |
1154 | }; | 1219 | }; |
1220 | |||
1221 | struct cpu_spec *identify_cpu(unsigned long offset, unsigned int pvr) | ||
1222 | { | ||
1223 | struct cpu_spec *s = cpu_specs; | ||
1224 | struct cpu_spec **cur = &cur_cpu_spec; | ||
1225 | int i; | ||
1226 | |||
1227 | s = PTRRELOC(s); | ||
1228 | cur = PTRRELOC(cur); | ||
1229 | |||
1230 | for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) | ||
1231 | if ((pvr & s->pvr_mask) == s->pvr_value) { | ||
1232 | *cur = cpu_specs + i; | ||
1233 | #ifdef CONFIG_PPC64 | ||
1234 | /* ppc64 expects identify_cpu to also call setup_cpu | ||
1235 | * for that processor. I will consolidate that at a | ||
1236 | * later time, for now, just use our friend #ifdef. | ||
1237 | * we also don't need to PTRRELOC the function pointer | ||
1238 | * on ppc64 as we are running at 0 in real mode. | ||
1239 | */ | ||
1240 | if (s->cpu_setup) { | ||
1241 | s->cpu_setup(offset, s); | ||
1242 | } | ||
1243 | #endif /* CONFIG_PPC64 */ | ||
1244 | return s; | ||
1245 | } | ||
1246 | BUG(); | ||
1247 | return NULL; | ||
1248 | } | ||
1249 | |||
1250 | void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) | ||
1251 | { | ||
1252 | struct fixup_entry { | ||
1253 | unsigned long mask; | ||
1254 | unsigned long value; | ||
1255 | long start_off; | ||
1256 | long end_off; | ||
1257 | } *fcur, *fend; | ||
1258 | |||
1259 | fcur = fixup_start; | ||
1260 | fend = fixup_end; | ||
1261 | |||
1262 | for (; fcur < fend; fcur++) { | ||
1263 | unsigned int *pstart, *pend, *p; | ||
1264 | |||
1265 | if ((value & fcur->mask) == fcur->value) | ||
1266 | continue; | ||
1267 | |||
1268 | /* These PTRRELOCs will disappear once the new scheme for | ||
1269 | * modules and vdso is implemented | ||
1270 | */ | ||
1271 | pstart = ((unsigned int *)fcur) + (fcur->start_off / 4); | ||
1272 | pend = ((unsigned int *)fcur) + (fcur->end_off / 4); | ||
1273 | |||
1274 | for (p = pstart; p < pend; p++) { | ||
1275 | *p = 0x60000000u; | ||
1276 | asm volatile ("dcbst 0, %0" : : "r" (p)); | ||
1277 | } | ||
1278 | asm volatile ("sync" : : : "memory"); | ||
1279 | for (p = pstart; p < pend; p++) | ||
1280 | asm volatile ("icbi 0,%0" : : "r" (p)); | ||
1281 | asm volatile ("sync; isync" : : : "memory"); | ||
1282 | } | ||
1283 | } | ||
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 1af41f7616dc..d3f2080d2eee 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -46,61 +46,6 @@ int crashing_cpu = -1; | |||
46 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; | 46 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; |
47 | cpumask_t cpus_in_sr = CPU_MASK_NONE; | 47 | cpumask_t cpus_in_sr = CPU_MASK_NONE; |
48 | 48 | ||
49 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | ||
50 | size_t data_len) | ||
51 | { | ||
52 | struct elf_note note; | ||
53 | |||
54 | note.n_namesz = strlen(name) + 1; | ||
55 | note.n_descsz = data_len; | ||
56 | note.n_type = type; | ||
57 | memcpy(buf, ¬e, sizeof(note)); | ||
58 | buf += (sizeof(note) +3)/4; | ||
59 | memcpy(buf, name, note.n_namesz); | ||
60 | buf += (note.n_namesz + 3)/4; | ||
61 | memcpy(buf, data, note.n_descsz); | ||
62 | buf += (note.n_descsz + 3)/4; | ||
63 | |||
64 | return buf; | ||
65 | } | ||
66 | |||
67 | static void final_note(u32 *buf) | ||
68 | { | ||
69 | struct elf_note note; | ||
70 | |||
71 | note.n_namesz = 0; | ||
72 | note.n_descsz = 0; | ||
73 | note.n_type = 0; | ||
74 | memcpy(buf, ¬e, sizeof(note)); | ||
75 | } | ||
76 | |||
77 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) | ||
78 | { | ||
79 | struct elf_prstatus prstatus; | ||
80 | u32 *buf; | ||
81 | |||
82 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
83 | return; | ||
84 | |||
85 | /* Using ELF notes here is opportunistic. | ||
86 | * I need a well defined structure format | ||
87 | * for the data I pass, and I need tags | ||
88 | * on the data to indicate what information I have | ||
89 | * squirrelled away. ELF notes happen to provide | ||
90 | * all of that that no need to invent something new. | ||
91 | */ | ||
92 | buf = (u32*)per_cpu_ptr(crash_notes, cpu); | ||
93 | if (!buf) | ||
94 | return; | ||
95 | |||
96 | memset(&prstatus, 0, sizeof(prstatus)); | ||
97 | prstatus.pr_pid = current->pid; | ||
98 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
99 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
100 | sizeof(prstatus)); | ||
101 | final_note(buf); | ||
102 | } | ||
103 | |||
104 | #ifdef CONFIG_SMP | 49 | #ifdef CONFIG_SMP |
105 | static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); | 50 | static atomic_t enter_on_soft_reset = ATOMIC_INIT(0); |
106 | 51 | ||
@@ -111,9 +56,9 @@ void crash_ipi_callback(struct pt_regs *regs) | |||
111 | if (!cpu_online(cpu)) | 56 | if (!cpu_online(cpu)) |
112 | return; | 57 | return; |
113 | 58 | ||
114 | local_irq_disable(); | 59 | hard_irq_disable(); |
115 | if (!cpu_isset(cpu, cpus_in_crash)) | 60 | if (!cpu_isset(cpu, cpus_in_crash)) |
116 | crash_save_this_cpu(regs, cpu); | 61 | crash_save_cpu(regs, cpu); |
117 | cpu_set(cpu, cpus_in_crash); | 62 | cpu_set(cpu, cpus_in_crash); |
118 | 63 | ||
119 | /* | 64 | /* |
@@ -289,7 +234,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
289 | * an SMP system. | 234 | * an SMP system. |
290 | * The kernel is broken so disable interrupts. | 235 | * The kernel is broken so disable interrupts. |
291 | */ | 236 | */ |
292 | local_irq_disable(); | 237 | hard_irq_disable(); |
293 | 238 | ||
294 | for_each_irq(irq) { | 239 | for_each_irq(irq) { |
295 | struct irq_desc *desc = irq_desc + irq; | 240 | struct irq_desc *desc = irq_desc + irq; |
@@ -306,7 +251,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
306 | * such that another IPI will not be sent. | 251 | * such that another IPI will not be sent. |
307 | */ | 252 | */ |
308 | crashing_cpu = smp_processor_id(); | 253 | crashing_cpu = smp_processor_id(); |
309 | crash_save_this_cpu(regs, crashing_cpu); | 254 | crash_save_cpu(regs, crashing_cpu); |
310 | crash_kexec_prepare_cpus(crashing_cpu); | 255 | crash_kexec_prepare_cpus(crashing_cpu); |
311 | cpu_set(crashing_cpu, cpus_in_crash); | 256 | cpu_set(crashing_cpu, cpus_in_crash); |
312 | if (ppc_md.kexec_cpu_down) | 257 | if (ppc_md.kexec_cpu_down) |
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 6c168f6ea142..7b0e754383cf 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c | |||
@@ -1,151 +1,194 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2004 IBM Corporation | 2 | * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation |
3 | * | 3 | * |
4 | * Implements the generic device dma API for ppc64. Handles | 4 | * Provide default implementations of the DMA mapping callbacks for |
5 | * the pci and vio busses | 5 | * directly mapped busses and busses using the iommu infrastructure |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/device.h> | 8 | #include <linux/device.h> |
9 | #include <linux/dma-mapping.h> | 9 | #include <linux/dma-mapping.h> |
10 | /* Include the busses we support */ | ||
11 | #include <linux/pci.h> | ||
12 | #include <asm/vio.h> | ||
13 | #include <asm/ibmebus.h> | ||
14 | #include <asm/scatterlist.h> | ||
15 | #include <asm/bug.h> | 10 | #include <asm/bug.h> |
11 | #include <asm/iommu.h> | ||
12 | #include <asm/abs_addr.h> | ||
16 | 13 | ||
17 | static struct dma_mapping_ops *get_dma_ops(struct device *dev) | 14 | /* |
18 | { | 15 | * Generic iommu implementation |
19 | #ifdef CONFIG_PCI | 16 | */ |
20 | if (dev->bus == &pci_bus_type) | ||
21 | return &pci_dma_ops; | ||
22 | #endif | ||
23 | #ifdef CONFIG_IBMVIO | ||
24 | if (dev->bus == &vio_bus_type) | ||
25 | return &vio_dma_ops; | ||
26 | #endif | ||
27 | #ifdef CONFIG_IBMEBUS | ||
28 | if (dev->bus == &ibmebus_bus_type) | ||
29 | return &ibmebus_dma_ops; | ||
30 | #endif | ||
31 | return NULL; | ||
32 | } | ||
33 | 17 | ||
34 | int dma_supported(struct device *dev, u64 mask) | 18 | static inline unsigned long device_to_mask(struct device *dev) |
35 | { | 19 | { |
36 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 20 | if (dev->dma_mask && *dev->dma_mask) |
21 | return *dev->dma_mask; | ||
22 | /* Assume devices without mask can take 32 bit addresses */ | ||
23 | return 0xfffffffful; | ||
24 | } | ||
37 | 25 | ||
38 | BUG_ON(!dma_ops); | ||
39 | 26 | ||
40 | return dma_ops->dma_supported(dev, mask); | 27 | /* Allocates a contiguous real buffer and creates mappings over it. |
28 | * Returns the virtual address of the buffer and sets dma_handle | ||
29 | * to the dma address (mapping) of the first page. | ||
30 | */ | ||
31 | static void *dma_iommu_alloc_coherent(struct device *dev, size_t size, | ||
32 | dma_addr_t *dma_handle, gfp_t flag) | ||
33 | { | ||
34 | return iommu_alloc_coherent(dev->archdata.dma_data, size, dma_handle, | ||
35 | device_to_mask(dev), flag, | ||
36 | dev->archdata.numa_node); | ||
41 | } | 37 | } |
42 | EXPORT_SYMBOL(dma_supported); | ||
43 | 38 | ||
44 | int dma_set_mask(struct device *dev, u64 dma_mask) | 39 | static void dma_iommu_free_coherent(struct device *dev, size_t size, |
40 | void *vaddr, dma_addr_t dma_handle) | ||
45 | { | 41 | { |
46 | #ifdef CONFIG_PCI | 42 | iommu_free_coherent(dev->archdata.dma_data, size, vaddr, dma_handle); |
47 | if (dev->bus == &pci_bus_type) | ||
48 | return pci_set_dma_mask(to_pci_dev(dev), dma_mask); | ||
49 | #endif | ||
50 | #ifdef CONFIG_IBMVIO | ||
51 | if (dev->bus == &vio_bus_type) | ||
52 | return -EIO; | ||
53 | #endif /* CONFIG_IBMVIO */ | ||
54 | #ifdef CONFIG_IBMEBUS | ||
55 | if (dev->bus == &ibmebus_bus_type) | ||
56 | return -EIO; | ||
57 | #endif | ||
58 | BUG(); | ||
59 | return 0; | ||
60 | } | 43 | } |
61 | EXPORT_SYMBOL(dma_set_mask); | ||
62 | 44 | ||
63 | void *dma_alloc_coherent(struct device *dev, size_t size, | 45 | /* Creates TCEs for a user provided buffer. The user buffer must be |
64 | dma_addr_t *dma_handle, gfp_t flag) | 46 | * contiguous real kernel storage (not vmalloc). The address of the buffer |
47 | * passed here is the kernel (virtual) address of the buffer. The buffer | ||
48 | * need not be page aligned, the dma_addr_t returned will point to the same | ||
49 | * byte within the page as vaddr. | ||
50 | */ | ||
51 | static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr, | ||
52 | size_t size, | ||
53 | enum dma_data_direction direction) | ||
65 | { | 54 | { |
66 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 55 | return iommu_map_single(dev->archdata.dma_data, vaddr, size, |
67 | 56 | device_to_mask(dev), direction); | |
68 | BUG_ON(!dma_ops); | ||
69 | |||
70 | return dma_ops->alloc_coherent(dev, size, dma_handle, flag); | ||
71 | } | 57 | } |
72 | EXPORT_SYMBOL(dma_alloc_coherent); | ||
73 | 58 | ||
74 | void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, | 59 | |
75 | dma_addr_t dma_handle) | 60 | static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle, |
61 | size_t size, | ||
62 | enum dma_data_direction direction) | ||
76 | { | 63 | { |
77 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 64 | iommu_unmap_single(dev->archdata.dma_data, dma_handle, size, direction); |
65 | } | ||
78 | 66 | ||
79 | BUG_ON(!dma_ops); | ||
80 | 67 | ||
81 | dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); | 68 | static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, |
69 | int nelems, enum dma_data_direction direction) | ||
70 | { | ||
71 | return iommu_map_sg(dev->archdata.dma_data, sglist, nelems, | ||
72 | device_to_mask(dev), direction); | ||
82 | } | 73 | } |
83 | EXPORT_SYMBOL(dma_free_coherent); | ||
84 | 74 | ||
85 | dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, | 75 | static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, |
86 | enum dma_data_direction direction) | 76 | int nelems, enum dma_data_direction direction) |
87 | { | 77 | { |
88 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 78 | iommu_unmap_sg(dev->archdata.dma_data, sglist, nelems, direction); |
89 | |||
90 | BUG_ON(!dma_ops); | ||
91 | |||
92 | return dma_ops->map_single(dev, cpu_addr, size, direction); | ||
93 | } | 79 | } |
94 | EXPORT_SYMBOL(dma_map_single); | ||
95 | 80 | ||
96 | void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, | 81 | /* We support DMA to/from any memory page via the iommu */ |
97 | enum dma_data_direction direction) | 82 | static int dma_iommu_dma_supported(struct device *dev, u64 mask) |
98 | { | 83 | { |
99 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 84 | struct iommu_table *tbl = dev->archdata.dma_data; |
100 | 85 | ||
101 | BUG_ON(!dma_ops); | 86 | if (!tbl || tbl->it_offset > mask) { |
102 | 87 | printk(KERN_INFO | |
103 | dma_ops->unmap_single(dev, dma_addr, size, direction); | 88 | "Warning: IOMMU offset too big for device mask\n"); |
89 | if (tbl) | ||
90 | printk(KERN_INFO | ||
91 | "mask: 0x%08lx, table offset: 0x%08lx\n", | ||
92 | mask, tbl->it_offset); | ||
93 | else | ||
94 | printk(KERN_INFO "mask: 0x%08lx, table unavailable\n", | ||
95 | mask); | ||
96 | return 0; | ||
97 | } else | ||
98 | return 1; | ||
104 | } | 99 | } |
105 | EXPORT_SYMBOL(dma_unmap_single); | ||
106 | 100 | ||
107 | dma_addr_t dma_map_page(struct device *dev, struct page *page, | 101 | struct dma_mapping_ops dma_iommu_ops = { |
108 | unsigned long offset, size_t size, | 102 | .alloc_coherent = dma_iommu_alloc_coherent, |
109 | enum dma_data_direction direction) | 103 | .free_coherent = dma_iommu_free_coherent, |
110 | { | 104 | .map_single = dma_iommu_map_single, |
111 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 105 | .unmap_single = dma_iommu_unmap_single, |
106 | .map_sg = dma_iommu_map_sg, | ||
107 | .unmap_sg = dma_iommu_unmap_sg, | ||
108 | .dma_supported = dma_iommu_dma_supported, | ||
109 | }; | ||
110 | EXPORT_SYMBOL(dma_iommu_ops); | ||
112 | 111 | ||
113 | BUG_ON(!dma_ops); | 112 | /* |
113 | * Generic direct DMA implementation | ||
114 | * | ||
115 | * This implementation supports a global offset that can be applied if | ||
116 | * the address at which memory is visible to devices is not 0. | ||
117 | */ | ||
118 | unsigned long dma_direct_offset; | ||
114 | 119 | ||
115 | return dma_ops->map_single(dev, page_address(page) + offset, size, | 120 | static void *dma_direct_alloc_coherent(struct device *dev, size_t size, |
116 | direction); | 121 | dma_addr_t *dma_handle, gfp_t flag) |
122 | { | ||
123 | struct page *page; | ||
124 | void *ret; | ||
125 | int node = dev->archdata.numa_node; | ||
126 | |||
127 | /* TODO: Maybe use the numa node here too ? */ | ||
128 | page = alloc_pages_node(node, flag, get_order(size)); | ||
129 | if (page == NULL) | ||
130 | return NULL; | ||
131 | ret = page_address(page); | ||
132 | memset(ret, 0, size); | ||
133 | *dma_handle = virt_to_abs(ret) | dma_direct_offset; | ||
134 | |||
135 | return ret; | ||
117 | } | 136 | } |
118 | EXPORT_SYMBOL(dma_map_page); | ||
119 | 137 | ||
120 | void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, | 138 | static void dma_direct_free_coherent(struct device *dev, size_t size, |
121 | enum dma_data_direction direction) | 139 | void *vaddr, dma_addr_t dma_handle) |
122 | { | 140 | { |
123 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 141 | free_pages((unsigned long)vaddr, get_order(size)); |
142 | } | ||
124 | 143 | ||
125 | BUG_ON(!dma_ops); | 144 | static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr, |
145 | size_t size, | ||
146 | enum dma_data_direction direction) | ||
147 | { | ||
148 | return virt_to_abs(ptr) | dma_direct_offset; | ||
149 | } | ||
126 | 150 | ||
127 | dma_ops->unmap_single(dev, dma_address, size, direction); | 151 | static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr, |
152 | size_t size, | ||
153 | enum dma_data_direction direction) | ||
154 | { | ||
128 | } | 155 | } |
129 | EXPORT_SYMBOL(dma_unmap_page); | ||
130 | 156 | ||
131 | int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | 157 | static int dma_direct_map_sg(struct device *dev, struct scatterlist *sg, |
132 | enum dma_data_direction direction) | 158 | int nents, enum dma_data_direction direction) |
133 | { | 159 | { |
134 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 160 | int i; |
135 | 161 | ||
136 | BUG_ON(!dma_ops); | 162 | for (i = 0; i < nents; i++, sg++) { |
163 | sg->dma_address = (page_to_phys(sg->page) + sg->offset) | | ||
164 | dma_direct_offset; | ||
165 | sg->dma_length = sg->length; | ||
166 | } | ||
137 | 167 | ||
138 | return dma_ops->map_sg(dev, sg, nents, direction); | 168 | return nents; |
139 | } | 169 | } |
140 | EXPORT_SYMBOL(dma_map_sg); | ||
141 | 170 | ||
142 | void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | 171 | static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, |
143 | enum dma_data_direction direction) | 172 | int nents, enum dma_data_direction direction) |
144 | { | 173 | { |
145 | struct dma_mapping_ops *dma_ops = get_dma_ops(dev); | 174 | } |
146 | |||
147 | BUG_ON(!dma_ops); | ||
148 | 175 | ||
149 | dma_ops->unmap_sg(dev, sg, nhwentries, direction); | 176 | static int dma_direct_dma_supported(struct device *dev, u64 mask) |
177 | { | ||
178 | /* Could be improved to check for memory though it better be | ||
179 | * done via some global so platforms can set the limit in case | ||
180 | * they have limited DMA windows | ||
181 | */ | ||
182 | return mask >= DMA_32BIT_MASK; | ||
150 | } | 183 | } |
151 | EXPORT_SYMBOL(dma_unmap_sg); | 184 | |
185 | struct dma_mapping_ops dma_direct_ops = { | ||
186 | .alloc_coherent = dma_direct_alloc_coherent, | ||
187 | .free_coherent = dma_direct_free_coherent, | ||
188 | .map_single = dma_direct_map_single, | ||
189 | .unmap_single = dma_direct_unmap_single, | ||
190 | .map_sg = dma_direct_map_sg, | ||
191 | .unmap_sg = dma_direct_unmap_sg, | ||
192 | .dma_supported = dma_direct_dma_supported, | ||
193 | }; | ||
194 | EXPORT_SYMBOL(dma_direct_ops); | ||
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 748e74fcf541..1a3d4de197d2 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -87,15 +87,19 @@ system_call_common: | |||
87 | addi r9,r1,STACK_FRAME_OVERHEAD | 87 | addi r9,r1,STACK_FRAME_OVERHEAD |
88 | ld r11,exception_marker@toc(r2) | 88 | ld r11,exception_marker@toc(r2) |
89 | std r11,-16(r9) /* "regshere" marker */ | 89 | std r11,-16(r9) /* "regshere" marker */ |
90 | li r10,1 | ||
91 | stb r10,PACASOFTIRQEN(r13) | ||
92 | stb r10,PACAHARDIRQEN(r13) | ||
93 | std r10,SOFTE(r1) | ||
90 | #ifdef CONFIG_PPC_ISERIES | 94 | #ifdef CONFIG_PPC_ISERIES |
91 | BEGIN_FW_FTR_SECTION | 95 | BEGIN_FW_FTR_SECTION |
92 | /* Hack for handling interrupts when soft-enabling on iSeries */ | 96 | /* Hack for handling interrupts when soft-enabling on iSeries */ |
93 | cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ | 97 | cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ |
94 | andi. r10,r12,MSR_PR /* from kernel */ | 98 | andi. r10,r12,MSR_PR /* from kernel */ |
95 | crand 4*cr0+eq,4*cr1+eq,4*cr0+eq | 99 | crand 4*cr0+eq,4*cr1+eq,4*cr0+eq |
96 | beq hardware_interrupt_entry | 100 | bne 2f |
97 | lbz r10,PACAPROCENABLED(r13) | 101 | b hardware_interrupt_entry |
98 | std r10,SOFTE(r1) | 102 | 2: |
99 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 103 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
100 | #endif | 104 | #endif |
101 | mfmsr r11 | 105 | mfmsr r11 |
@@ -460,9 +464,9 @@ _GLOBAL(ret_from_except_lite) | |||
460 | #endif | 464 | #endif |
461 | 465 | ||
462 | restore: | 466 | restore: |
467 | ld r5,SOFTE(r1) | ||
463 | #ifdef CONFIG_PPC_ISERIES | 468 | #ifdef CONFIG_PPC_ISERIES |
464 | BEGIN_FW_FTR_SECTION | 469 | BEGIN_FW_FTR_SECTION |
465 | ld r5,SOFTE(r1) | ||
466 | cmpdi 0,r5,0 | 470 | cmpdi 0,r5,0 |
467 | beq 4f | 471 | beq 4f |
468 | /* Check for pending interrupts (iSeries) */ | 472 | /* Check for pending interrupts (iSeries) */ |
@@ -472,21 +476,25 @@ BEGIN_FW_FTR_SECTION | |||
472 | beq+ 4f /* skip do_IRQ if no interrupts */ | 476 | beq+ 4f /* skip do_IRQ if no interrupts */ |
473 | 477 | ||
474 | li r3,0 | 478 | li r3,0 |
475 | stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */ | 479 | stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */ |
476 | ori r10,r10,MSR_EE | 480 | ori r10,r10,MSR_EE |
477 | mtmsrd r10 /* hard-enable again */ | 481 | mtmsrd r10 /* hard-enable again */ |
478 | addi r3,r1,STACK_FRAME_OVERHEAD | 482 | addi r3,r1,STACK_FRAME_OVERHEAD |
479 | bl .do_IRQ | 483 | bl .do_IRQ |
480 | b .ret_from_except_lite /* loop back and handle more */ | 484 | b .ret_from_except_lite /* loop back and handle more */ |
481 | 485 | 4: | |
482 | 4: stb r5,PACAPROCENABLED(r13) | ||
483 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 486 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
484 | #endif | 487 | #endif |
488 | stb r5,PACASOFTIRQEN(r13) | ||
485 | 489 | ||
486 | ld r3,_MSR(r1) | 490 | ld r3,_MSR(r1) |
487 | andi. r0,r3,MSR_RI | 491 | andi. r0,r3,MSR_RI |
488 | beq- unrecov_restore | 492 | beq- unrecov_restore |
489 | 493 | ||
494 | /* extract EE bit and use it to restore paca->hard_enabled */ | ||
495 | rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ | ||
496 | stb r4,PACAHARDIRQEN(r13) | ||
497 | |||
490 | andi. r0,r3,MSR_PR | 498 | andi. r0,r3,MSR_PR |
491 | 499 | ||
492 | /* | 500 | /* |
@@ -538,25 +546,15 @@ do_work: | |||
538 | /* Check that preempt_count() == 0 and interrupts are enabled */ | 546 | /* Check that preempt_count() == 0 and interrupts are enabled */ |
539 | lwz r8,TI_PREEMPT(r9) | 547 | lwz r8,TI_PREEMPT(r9) |
540 | cmpwi cr1,r8,0 | 548 | cmpwi cr1,r8,0 |
541 | #ifdef CONFIG_PPC_ISERIES | ||
542 | BEGIN_FW_FTR_SECTION | ||
543 | ld r0,SOFTE(r1) | 549 | ld r0,SOFTE(r1) |
544 | cmpdi r0,0 | 550 | cmpdi r0,0 |
545 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
546 | #endif | ||
547 | BEGIN_FW_FTR_SECTION | ||
548 | andi. r0,r3,MSR_EE | ||
549 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
550 | crandc eq,cr1*4+eq,eq | 551 | crandc eq,cr1*4+eq,eq |
551 | bne restore | 552 | bne restore |
552 | /* here we are preempting the current task */ | 553 | /* here we are preempting the current task */ |
553 | 1: | 554 | 1: |
554 | #ifdef CONFIG_PPC_ISERIES | ||
555 | BEGIN_FW_FTR_SECTION | ||
556 | li r0,1 | 555 | li r0,1 |
557 | stb r0,PACAPROCENABLED(r13) | 556 | stb r0,PACASOFTIRQEN(r13) |
558 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 557 | stb r0,PACAHARDIRQEN(r13) |
559 | #endif | ||
560 | ori r10,r10,MSR_EE | 558 | ori r10,r10,MSR_EE |
561 | mtmsrd r10,1 /* reenable interrupts */ | 559 | mtmsrd r10,1 /* reenable interrupts */ |
562 | bl .preempt_schedule | 560 | bl .preempt_schedule |
@@ -639,8 +637,7 @@ _GLOBAL(enter_rtas) | |||
639 | /* There is no way it is acceptable to get here with interrupts enabled, | 637 | /* There is no way it is acceptable to get here with interrupts enabled, |
640 | * check it with the asm equivalent of WARN_ON | 638 | * check it with the asm equivalent of WARN_ON |
641 | */ | 639 | */ |
642 | mfmsr r6 | 640 | lbz r0,PACASOFTIRQEN(r13) |
643 | andi. r0,r6,MSR_EE | ||
644 | 1: tdnei r0,0 | 641 | 1: tdnei r0,0 |
645 | .section __bug_table,"a" | 642 | .section __bug_table,"a" |
646 | .llong 1b,__LINE__ + 0x1000000, 1f, 2f | 643 | .llong 1b,__LINE__ + 0x1000000, 1f, 2f |
@@ -649,7 +646,13 @@ _GLOBAL(enter_rtas) | |||
649 | 1: .asciz __FILE__ | 646 | 1: .asciz __FILE__ |
650 | 2: .asciz "enter_rtas" | 647 | 2: .asciz "enter_rtas" |
651 | .previous | 648 | .previous |
652 | 649 | ||
650 | /* Hard-disable interrupts */ | ||
651 | mfmsr r6 | ||
652 | rldicl r7,r6,48,1 | ||
653 | rotldi r7,r7,16 | ||
654 | mtmsrd r7,1 | ||
655 | |||
653 | /* Unfortunately, the stack pointer and the MSR are also clobbered, | 656 | /* Unfortunately, the stack pointer and the MSR are also clobbered, |
654 | * so they are saved in the PACA which allows us to restore | 657 | * so they are saved in the PACA which allows us to restore |
655 | * our original state after RTAS returns. | 658 | * our original state after RTAS returns. |
@@ -735,8 +738,6 @@ _STATIC(rtas_restore_regs) | |||
735 | 738 | ||
736 | #endif /* CONFIG_PPC_RTAS */ | 739 | #endif /* CONFIG_PPC_RTAS */ |
737 | 740 | ||
738 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
739 | |||
740 | _GLOBAL(enter_prom) | 741 | _GLOBAL(enter_prom) |
741 | mflr r0 | 742 | mflr r0 |
742 | std r0,16(r1) | 743 | std r0,16(r1) |
@@ -821,5 +822,3 @@ _GLOBAL(enter_prom) | |||
821 | ld r0,16(r1) | 822 | ld r0,16(r1) |
822 | mtlr r0 | 823 | mtlr r0 |
823 | blr | 824 | blr |
824 | |||
825 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index d88e182e40b3..9417cf5b4b7e 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S | |||
@@ -437,6 +437,13 @@ Alignment: | |||
437 | /* Floating-point unavailable */ | 437 | /* Floating-point unavailable */ |
438 | . = 0x800 | 438 | . = 0x800 |
439 | FPUnavailable: | 439 | FPUnavailable: |
440 | BEGIN_FTR_SECTION | ||
441 | /* | ||
442 | * Certain Freescale cores don't have a FPU and treat fp instructions | ||
443 | * as a FP Unavailable exception. Redirect to illegal/emulation handling. | ||
444 | */ | ||
445 | b ProgramCheck | ||
446 | END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE) | ||
440 | EXCEPTION_PROLOG | 447 | EXCEPTION_PROLOG |
441 | bne load_up_fpu /* if from user, just load it up */ | 448 | bne load_up_fpu /* if from user, just load it up */ |
442 | addi r3,r1,STACK_FRAME_OVERHEAD | 449 | addi r3,r1,STACK_FRAME_OVERHEAD |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 645c7f10fb28..71b1fe58e9e4 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -35,9 +35,7 @@ | |||
35 | #include <asm/thread_info.h> | 35 | #include <asm/thread_info.h> |
36 | #include <asm/firmware.h> | 36 | #include <asm/firmware.h> |
37 | 37 | ||
38 | #ifdef CONFIG_PPC_ISERIES | ||
39 | #define DO_SOFT_DISABLE | 38 | #define DO_SOFT_DISABLE |
40 | #endif | ||
41 | 39 | ||
42 | /* | 40 | /* |
43 | * We layout physical memory as follows: | 41 | * We layout physical memory as follows: |
@@ -74,13 +72,11 @@ | |||
74 | .text | 72 | .text |
75 | .globl _stext | 73 | .globl _stext |
76 | _stext: | 74 | _stext: |
77 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
78 | _GLOBAL(__start) | 75 | _GLOBAL(__start) |
79 | /* NOP this out unconditionally */ | 76 | /* NOP this out unconditionally */ |
80 | BEGIN_FTR_SECTION | 77 | BEGIN_FTR_SECTION |
81 | b .__start_initialization_multiplatform | 78 | b .__start_initialization_multiplatform |
82 | END_FTR_SECTION(0, 1) | 79 | END_FTR_SECTION(0, 1) |
83 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
84 | 80 | ||
85 | /* Catch branch to 0 in real mode */ | 81 | /* Catch branch to 0 in real mode */ |
86 | trap | 82 | trap |
@@ -308,7 +304,9 @@ exception_marker: | |||
308 | std r9,_LINK(r1); \ | 304 | std r9,_LINK(r1); \ |
309 | mfctr r10; /* save CTR in stackframe */ \ | 305 | mfctr r10; /* save CTR in stackframe */ \ |
310 | std r10,_CTR(r1); \ | 306 | std r10,_CTR(r1); \ |
307 | lbz r10,PACASOFTIRQEN(r13); \ | ||
311 | mfspr r11,SPRN_XER; /* save XER in stackframe */ \ | 308 | mfspr r11,SPRN_XER; /* save XER in stackframe */ \ |
309 | std r10,SOFTE(r1); \ | ||
312 | std r11,_XER(r1); \ | 310 | std r11,_XER(r1); \ |
313 | li r9,(n)+1; \ | 311 | li r9,(n)+1; \ |
314 | std r9,_TRAP(r1); /* set trap number */ \ | 312 | std r9,_TRAP(r1); /* set trap number */ \ |
@@ -343,6 +341,34 @@ label##_pSeries: \ | |||
343 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) | 341 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) |
344 | 342 | ||
345 | 343 | ||
344 | #define MASKABLE_EXCEPTION_PSERIES(n, label) \ | ||
345 | . = n; \ | ||
346 | .globl label##_pSeries; \ | ||
347 | label##_pSeries: \ | ||
348 | HMT_MEDIUM; \ | ||
349 | mtspr SPRN_SPRG1,r13; /* save r13 */ \ | ||
350 | mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ | ||
351 | std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ | ||
352 | std r10,PACA_EXGEN+EX_R10(r13); \ | ||
353 | lbz r10,PACASOFTIRQEN(r13); \ | ||
354 | mfcr r9; \ | ||
355 | cmpwi r10,0; \ | ||
356 | beq masked_interrupt; \ | ||
357 | mfspr r10,SPRN_SPRG1; \ | ||
358 | std r10,PACA_EXGEN+EX_R13(r13); \ | ||
359 | std r11,PACA_EXGEN+EX_R11(r13); \ | ||
360 | std r12,PACA_EXGEN+EX_R12(r13); \ | ||
361 | clrrdi r12,r13,32; /* get high part of &label */ \ | ||
362 | mfmsr r10; \ | ||
363 | mfspr r11,SPRN_SRR0; /* save SRR0 */ \ | ||
364 | LOAD_HANDLER(r12,label##_common) \ | ||
365 | ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ | ||
366 | mtspr SPRN_SRR0,r12; \ | ||
367 | mfspr r12,SPRN_SRR1; /* and SRR1 */ \ | ||
368 | mtspr SPRN_SRR1,r10; \ | ||
369 | rfid; \ | ||
370 | b . /* prevent speculative execution */ | ||
371 | |||
346 | #define STD_EXCEPTION_ISERIES(n, label, area) \ | 372 | #define STD_EXCEPTION_ISERIES(n, label, area) \ |
347 | .globl label##_iSeries; \ | 373 | .globl label##_iSeries; \ |
348 | label##_iSeries: \ | 374 | label##_iSeries: \ |
@@ -358,40 +384,32 @@ label##_iSeries: \ | |||
358 | HMT_MEDIUM; \ | 384 | HMT_MEDIUM; \ |
359 | mtspr SPRN_SPRG1,r13; /* save r13 */ \ | 385 | mtspr SPRN_SPRG1,r13; /* save r13 */ \ |
360 | EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ | 386 | EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ |
361 | lbz r10,PACAPROCENABLED(r13); \ | 387 | lbz r10,PACASOFTIRQEN(r13); \ |
362 | cmpwi 0,r10,0; \ | 388 | cmpwi 0,r10,0; \ |
363 | beq- label##_iSeries_masked; \ | 389 | beq- label##_iSeries_masked; \ |
364 | EXCEPTION_PROLOG_ISERIES_2; \ | 390 | EXCEPTION_PROLOG_ISERIES_2; \ |
365 | b label##_common; \ | 391 | b label##_common; \ |
366 | 392 | ||
367 | #ifdef DO_SOFT_DISABLE | 393 | #ifdef CONFIG_PPC_ISERIES |
368 | #define DISABLE_INTS \ | 394 | #define DISABLE_INTS \ |
369 | BEGIN_FW_FTR_SECTION; \ | ||
370 | lbz r10,PACAPROCENABLED(r13); \ | ||
371 | li r11,0; \ | 395 | li r11,0; \ |
372 | std r10,SOFTE(r1); \ | 396 | stb r11,PACASOFTIRQEN(r13); \ |
397 | BEGIN_FW_FTR_SECTION; \ | ||
398 | stb r11,PACAHARDIRQEN(r13); \ | ||
399 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | ||
400 | BEGIN_FW_FTR_SECTION; \ | ||
373 | mfmsr r10; \ | 401 | mfmsr r10; \ |
374 | stb r11,PACAPROCENABLED(r13); \ | ||
375 | ori r10,r10,MSR_EE; \ | 402 | ori r10,r10,MSR_EE; \ |
376 | mtmsrd r10,1; \ | 403 | mtmsrd r10,1; \ |
377 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 404 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
378 | 405 | ||
379 | #define ENABLE_INTS \ | 406 | #else |
380 | BEGIN_FW_FTR_SECTION; \ | 407 | #define DISABLE_INTS \ |
381 | lbz r10,PACAPROCENABLED(r13); \ | 408 | li r11,0; \ |
382 | mfmsr r11; \ | 409 | stb r11,PACASOFTIRQEN(r13); \ |
383 | std r10,SOFTE(r1); \ | 410 | stb r11,PACAHARDIRQEN(r13) |
384 | ori r11,r11,MSR_EE; \ | ||
385 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ | ||
386 | BEGIN_FW_FTR_SECTION; \ | ||
387 | ld r12,_MSR(r1); \ | ||
388 | mfmsr r11; \ | ||
389 | rlwimi r11,r12,0,MSR_EE; \ | ||
390 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | ||
391 | mtmsrd r11,1 | ||
392 | 411 | ||
393 | #else /* hard enable/disable interrupts */ | 412 | #endif /* CONFIG_PPC_ISERIES */ |
394 | #define DISABLE_INTS | ||
395 | 413 | ||
396 | #define ENABLE_INTS \ | 414 | #define ENABLE_INTS \ |
397 | ld r12,_MSR(r1); \ | 415 | ld r12,_MSR(r1); \ |
@@ -399,8 +417,6 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | |||
399 | rlwimi r11,r12,0,MSR_EE; \ | 417 | rlwimi r11,r12,0,MSR_EE; \ |
400 | mtmsrd r11,1 | 418 | mtmsrd r11,1 |
401 | 419 | ||
402 | #endif | ||
403 | |||
404 | #define STD_EXCEPTION_COMMON(trap, label, hdlr) \ | 420 | #define STD_EXCEPTION_COMMON(trap, label, hdlr) \ |
405 | .align 7; \ | 421 | .align 7; \ |
406 | .globl label##_common; \ | 422 | .globl label##_common; \ |
@@ -487,7 +503,7 @@ BEGIN_FTR_SECTION | |||
487 | rlwimi r13,r12,16,0x20 | 503 | rlwimi r13,r12,16,0x20 |
488 | mfcr r12 | 504 | mfcr r12 |
489 | cmpwi r13,0x2c | 505 | cmpwi r13,0x2c |
490 | beq .do_stab_bolted_pSeries | 506 | beq do_stab_bolted_pSeries |
491 | mtcrf 0x80,r12 | 507 | mtcrf 0x80,r12 |
492 | mfspr r12,SPRN_SPRG2 | 508 | mfspr r12,SPRN_SPRG2 |
493 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | 509 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) |
@@ -541,11 +557,11 @@ instruction_access_slb_pSeries: | |||
541 | mfspr r12,SPRN_SRR1 /* and SRR1 */ | 557 | mfspr r12,SPRN_SRR1 /* and SRR1 */ |
542 | b .slb_miss_realmode /* Rel. branch works in real mode */ | 558 | b .slb_miss_realmode /* Rel. branch works in real mode */ |
543 | 559 | ||
544 | STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) | 560 | MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt) |
545 | STD_EXCEPTION_PSERIES(0x600, alignment) | 561 | STD_EXCEPTION_PSERIES(0x600, alignment) |
546 | STD_EXCEPTION_PSERIES(0x700, program_check) | 562 | STD_EXCEPTION_PSERIES(0x700, program_check) |
547 | STD_EXCEPTION_PSERIES(0x800, fp_unavailable) | 563 | STD_EXCEPTION_PSERIES(0x800, fp_unavailable) |
548 | STD_EXCEPTION_PSERIES(0x900, decrementer) | 564 | MASKABLE_EXCEPTION_PSERIES(0x900, decrementer) |
549 | STD_EXCEPTION_PSERIES(0xa00, trap_0a) | 565 | STD_EXCEPTION_PSERIES(0xa00, trap_0a) |
550 | STD_EXCEPTION_PSERIES(0xb00, trap_0b) | 566 | STD_EXCEPTION_PSERIES(0xb00, trap_0b) |
551 | 567 | ||
@@ -597,10 +613,27 @@ system_call_pSeries: | |||
597 | /*** pSeries interrupt support ***/ | 613 | /*** pSeries interrupt support ***/ |
598 | 614 | ||
599 | /* moved from 0xf00 */ | 615 | /* moved from 0xf00 */ |
600 | STD_EXCEPTION_PSERIES(., performance_monitor) | 616 | MASKABLE_EXCEPTION_PSERIES(., performance_monitor) |
617 | |||
618 | /* | ||
619 | * An interrupt came in while soft-disabled; clear EE in SRR1, | ||
620 | * clear paca->hard_enabled and return. | ||
621 | */ | ||
622 | masked_interrupt: | ||
623 | stb r10,PACAHARDIRQEN(r13) | ||
624 | mtcrf 0x80,r9 | ||
625 | ld r9,PACA_EXGEN+EX_R9(r13) | ||
626 | mfspr r10,SPRN_SRR1 | ||
627 | rldicl r10,r10,48,1 /* clear MSR_EE */ | ||
628 | rotldi r10,r10,16 | ||
629 | mtspr SPRN_SRR1,r10 | ||
630 | ld r10,PACA_EXGEN+EX_R10(r13) | ||
631 | mfspr r13,SPRN_SPRG1 | ||
632 | rfid | ||
633 | b . | ||
601 | 634 | ||
602 | .align 7 | 635 | .align 7 |
603 | _GLOBAL(do_stab_bolted_pSeries) | 636 | do_stab_bolted_pSeries: |
604 | mtcrf 0x80,r12 | 637 | mtcrf 0x80,r12 |
605 | mfspr r12,SPRN_SPRG2 | 638 | mfspr r12,SPRN_SPRG2 |
606 | EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) | 639 | EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) |
@@ -792,7 +825,7 @@ system_reset_iSeries: | |||
792 | 825 | ||
793 | cmpwi 0,r23,0 | 826 | cmpwi 0,r23,0 |
794 | beq iSeries_secondary_smp_loop /* Loop until told to go */ | 827 | beq iSeries_secondary_smp_loop /* Loop until told to go */ |
795 | bne .__secondary_start /* Loop until told to go */ | 828 | bne __secondary_start /* Loop until told to go */ |
796 | iSeries_secondary_smp_loop: | 829 | iSeries_secondary_smp_loop: |
797 | /* Let the Hypervisor know we are alive */ | 830 | /* Let the Hypervisor know we are alive */ |
798 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | 831 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ |
@@ -813,7 +846,6 @@ iSeries_secondary_smp_loop: | |||
813 | b 1b /* If SMP not configured, secondaries | 846 | b 1b /* If SMP not configured, secondaries |
814 | * loop forever */ | 847 | * loop forever */ |
815 | 848 | ||
816 | .globl decrementer_iSeries_masked | ||
817 | decrementer_iSeries_masked: | 849 | decrementer_iSeries_masked: |
818 | /* We may not have a valid TOC pointer in here. */ | 850 | /* We may not have a valid TOC pointer in here. */ |
819 | li r11,1 | 851 | li r11,1 |
@@ -824,7 +856,6 @@ decrementer_iSeries_masked: | |||
824 | mtspr SPRN_DEC,r12 | 856 | mtspr SPRN_DEC,r12 |
825 | /* fall through */ | 857 | /* fall through */ |
826 | 858 | ||
827 | .globl hardware_interrupt_iSeries_masked | ||
828 | hardware_interrupt_iSeries_masked: | 859 | hardware_interrupt_iSeries_masked: |
829 | mtcrf 0x80,r9 /* Restore regs */ | 860 | mtcrf 0x80,r9 /* Restore regs */ |
830 | ld r12,PACALPPACAPTR(r13) | 861 | ld r12,PACALPPACAPTR(r13) |
@@ -926,10 +957,18 @@ bad_stack: | |||
926 | * any task or sent any task a signal, you should use | 957 | * any task or sent any task a signal, you should use |
927 | * ret_from_except or ret_from_except_lite instead of this. | 958 | * ret_from_except or ret_from_except_lite instead of this. |
928 | */ | 959 | */ |
960 | fast_exc_return_irq: /* restores irq state too */ | ||
961 | ld r3,SOFTE(r1) | ||
962 | ld r12,_MSR(r1) | ||
963 | stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ | ||
964 | rldicl r4,r12,49,63 /* get MSR_EE to LSB */ | ||
965 | stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ | ||
966 | b 1f | ||
967 | |||
929 | .globl fast_exception_return | 968 | .globl fast_exception_return |
930 | fast_exception_return: | 969 | fast_exception_return: |
931 | ld r12,_MSR(r1) | 970 | ld r12,_MSR(r1) |
932 | ld r11,_NIP(r1) | 971 | 1: ld r11,_NIP(r1) |
933 | andi. r3,r12,MSR_RI /* check if RI is set */ | 972 | andi. r3,r12,MSR_RI /* check if RI is set */ |
934 | beq- unrecov_fer | 973 | beq- unrecov_fer |
935 | 974 | ||
@@ -952,7 +991,8 @@ fast_exception_return: | |||
952 | REST_8GPRS(2, r1) | 991 | REST_8GPRS(2, r1) |
953 | 992 | ||
954 | mfmsr r10 | 993 | mfmsr r10 |
955 | clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ | 994 | rldicl r10,r10,48,1 /* clear EE */ |
995 | rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */ | ||
956 | mtmsrd r10,1 | 996 | mtmsrd r10,1 |
957 | 997 | ||
958 | mtspr SPRN_SRR1,r12 | 998 | mtspr SPRN_SRR1,r12 |
@@ -1046,7 +1086,7 @@ slb_miss_fault: | |||
1046 | li r5,0 | 1086 | li r5,0 |
1047 | std r4,_DAR(r1) | 1087 | std r4,_DAR(r1) |
1048 | std r5,_DSISR(r1) | 1088 | std r5,_DSISR(r1) |
1049 | b .handle_page_fault | 1089 | b handle_page_fault |
1050 | 1090 | ||
1051 | unrecov_user_slb: | 1091 | unrecov_user_slb: |
1052 | EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN) | 1092 | EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN) |
@@ -1174,12 +1214,13 @@ program_check_common: | |||
1174 | .globl fp_unavailable_common | 1214 | .globl fp_unavailable_common |
1175 | fp_unavailable_common: | 1215 | fp_unavailable_common: |
1176 | EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) | 1216 | EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) |
1177 | bne .load_up_fpu /* if from user, just load it up */ | 1217 | bne 1f /* if from user, just load it up */ |
1178 | bl .save_nvgprs | 1218 | bl .save_nvgprs |
1179 | addi r3,r1,STACK_FRAME_OVERHEAD | 1219 | addi r3,r1,STACK_FRAME_OVERHEAD |
1180 | ENABLE_INTS | 1220 | ENABLE_INTS |
1181 | bl .kernel_fp_unavailable_exception | 1221 | bl .kernel_fp_unavailable_exception |
1182 | BUG_OPCODE | 1222 | BUG_OPCODE |
1223 | 1: b .load_up_fpu | ||
1183 | 1224 | ||
1184 | .align 7 | 1225 | .align 7 |
1185 | .globl altivec_unavailable_common | 1226 | .globl altivec_unavailable_common |
@@ -1279,10 +1320,10 @@ _GLOBAL(do_hash_page) | |||
1279 | std r4,_DSISR(r1) | 1320 | std r4,_DSISR(r1) |
1280 | 1321 | ||
1281 | andis. r0,r4,0xa450 /* weird error? */ | 1322 | andis. r0,r4,0xa450 /* weird error? */ |
1282 | bne- .handle_page_fault /* if not, try to insert a HPTE */ | 1323 | bne- handle_page_fault /* if not, try to insert a HPTE */ |
1283 | BEGIN_FTR_SECTION | 1324 | BEGIN_FTR_SECTION |
1284 | andis. r0,r4,0x0020 /* Is it a segment table fault? */ | 1325 | andis. r0,r4,0x0020 /* Is it a segment table fault? */ |
1285 | bne- .do_ste_alloc /* If so handle it */ | 1326 | bne- do_ste_alloc /* If so handle it */ |
1286 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | 1327 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) |
1287 | 1328 | ||
1288 | /* | 1329 | /* |
@@ -1324,7 +1365,17 @@ BEGIN_FW_FTR_SECTION | |||
1324 | * because ret_from_except_lite will check for and handle pending | 1365 | * because ret_from_except_lite will check for and handle pending |
1325 | * interrupts if necessary. | 1366 | * interrupts if necessary. |
1326 | */ | 1367 | */ |
1327 | beq .ret_from_except_lite | 1368 | beq 13f |
1369 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1370 | #endif | ||
1371 | BEGIN_FW_FTR_SECTION | ||
1372 | /* | ||
1373 | * Here we have interrupts hard-disabled, so it is sufficient | ||
1374 | * to restore paca->{soft,hard}_enable and get out. | ||
1375 | */ | ||
1376 | beq fast_exc_return_irq /* Return from exception on success */ | ||
1377 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
1378 | |||
1328 | /* For a hash failure, we don't bother re-enabling interrupts */ | 1379 | /* For a hash failure, we don't bother re-enabling interrupts */ |
1329 | ble- 12f | 1380 | ble- 12f |
1330 | 1381 | ||
@@ -1336,24 +1387,16 @@ BEGIN_FW_FTR_SECTION | |||
1336 | ld r3,SOFTE(r1) | 1387 | ld r3,SOFTE(r1) |
1337 | bl .local_irq_restore | 1388 | bl .local_irq_restore |
1338 | b 11f | 1389 | b 11f |
1339 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1340 | #endif | ||
1341 | BEGIN_FW_FTR_SECTION | ||
1342 | beq fast_exception_return /* Return from exception on success */ | ||
1343 | ble- 12f /* Failure return from hash_page */ | ||
1344 | |||
1345 | /* fall through */ | ||
1346 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
1347 | 1390 | ||
1348 | /* Here we have a page fault that hash_page can't handle. */ | 1391 | /* Here we have a page fault that hash_page can't handle. */ |
1349 | _GLOBAL(handle_page_fault) | 1392 | handle_page_fault: |
1350 | ENABLE_INTS | 1393 | ENABLE_INTS |
1351 | 11: ld r4,_DAR(r1) | 1394 | 11: ld r4,_DAR(r1) |
1352 | ld r5,_DSISR(r1) | 1395 | ld r5,_DSISR(r1) |
1353 | addi r3,r1,STACK_FRAME_OVERHEAD | 1396 | addi r3,r1,STACK_FRAME_OVERHEAD |
1354 | bl .do_page_fault | 1397 | bl .do_page_fault |
1355 | cmpdi r3,0 | 1398 | cmpdi r3,0 |
1356 | beq+ .ret_from_except_lite | 1399 | beq+ 13f |
1357 | bl .save_nvgprs | 1400 | bl .save_nvgprs |
1358 | mr r5,r3 | 1401 | mr r5,r3 |
1359 | addi r3,r1,STACK_FRAME_OVERHEAD | 1402 | addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -1361,6 +1404,8 @@ _GLOBAL(handle_page_fault) | |||
1361 | bl .bad_page_fault | 1404 | bl .bad_page_fault |
1362 | b .ret_from_except | 1405 | b .ret_from_except |
1363 | 1406 | ||
1407 | 13: b .ret_from_except_lite | ||
1408 | |||
1364 | /* We have a page fault that hash_page could handle but HV refused | 1409 | /* We have a page fault that hash_page could handle but HV refused |
1365 | * the PTE insertion | 1410 | * the PTE insertion |
1366 | */ | 1411 | */ |
@@ -1371,11 +1416,11 @@ _GLOBAL(handle_page_fault) | |||
1371 | b .ret_from_except | 1416 | b .ret_from_except |
1372 | 1417 | ||
1373 | /* here we have a segment miss */ | 1418 | /* here we have a segment miss */ |
1374 | _GLOBAL(do_ste_alloc) | 1419 | do_ste_alloc: |
1375 | bl .ste_allocate /* try to insert stab entry */ | 1420 | bl .ste_allocate /* try to insert stab entry */ |
1376 | cmpdi r3,0 | 1421 | cmpdi r3,0 |
1377 | beq+ fast_exception_return | 1422 | bne- handle_page_fault |
1378 | b .handle_page_fault | 1423 | b fast_exception_return |
1379 | 1424 | ||
1380 | /* | 1425 | /* |
1381 | * r13 points to the PACA, r9 contains the saved CR, | 1426 | * r13 points to the PACA, r9 contains the saved CR, |
@@ -1557,7 +1602,7 @@ _GLOBAL(generic_secondary_smp_init) | |||
1557 | ld r1,PACAEMERGSP(r13) | 1602 | ld r1,PACAEMERGSP(r13) |
1558 | subi r1,r1,STACK_FRAME_OVERHEAD | 1603 | subi r1,r1,STACK_FRAME_OVERHEAD |
1559 | 1604 | ||
1560 | b .__secondary_start | 1605 | b __secondary_start |
1561 | #endif | 1606 | #endif |
1562 | 1607 | ||
1563 | #ifdef CONFIG_PPC_ISERIES | 1608 | #ifdef CONFIG_PPC_ISERIES |
@@ -1580,11 +1625,6 @@ _STATIC(__start_initialization_iSeries) | |||
1580 | li r0,0 | 1625 | li r0,0 |
1581 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | 1626 | stdu r0,-STACK_FRAME_OVERHEAD(r1) |
1582 | 1627 | ||
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) | 1628 | LOAD_REG_IMMEDIATE(r2,__toc_start) |
1589 | addi r2,r2,0x4000 | 1629 | addi r2,r2,0x4000 |
1590 | addi r2,r2,0x4000 | 1630 | addi r2,r2,0x4000 |
@@ -1597,7 +1637,6 @@ _STATIC(__start_initialization_iSeries) | |||
1597 | b .start_here_common | 1637 | b .start_here_common |
1598 | #endif /* CONFIG_PPC_ISERIES */ | 1638 | #endif /* CONFIG_PPC_ISERIES */ |
1599 | 1639 | ||
1600 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1601 | 1640 | ||
1602 | _STATIC(__mmu_off) | 1641 | _STATIC(__mmu_off) |
1603 | mfmsr r3 | 1642 | mfmsr r3 |
@@ -1623,13 +1662,11 @@ _STATIC(__mmu_off) | |||
1623 | * | 1662 | * |
1624 | */ | 1663 | */ |
1625 | _GLOBAL(__start_initialization_multiplatform) | 1664 | _GLOBAL(__start_initialization_multiplatform) |
1626 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1627 | /* | 1665 | /* |
1628 | * Are we booted from a PROM Of-type client-interface ? | 1666 | * Are we booted from a PROM Of-type client-interface ? |
1629 | */ | 1667 | */ |
1630 | cmpldi cr0,r5,0 | 1668 | cmpldi cr0,r5,0 |
1631 | bne .__boot_from_prom /* yes -> prom */ | 1669 | bne .__boot_from_prom /* yes -> prom */ |
1632 | #endif | ||
1633 | 1670 | ||
1634 | /* Save parameters */ | 1671 | /* Save parameters */ |
1635 | mr r31,r3 | 1672 | mr r31,r3 |
@@ -1646,6 +1683,8 @@ _GLOBAL(__start_initialization_multiplatform) | |||
1646 | cmpwi r0,0x3c /* 970FX */ | 1683 | cmpwi r0,0x3c /* 970FX */ |
1647 | beq 1f | 1684 | beq 1f |
1648 | cmpwi r0,0x44 /* 970MP */ | 1685 | cmpwi r0,0x44 /* 970MP */ |
1686 | beq 1f | ||
1687 | cmpwi r0,0x45 /* 970GX */ | ||
1649 | bne 2f | 1688 | bne 2f |
1650 | 1: bl .__cpu_preinit_ppc970 | 1689 | 1: bl .__cpu_preinit_ppc970 |
1651 | 2: | 1690 | 2: |
@@ -1656,7 +1695,6 @@ _GLOBAL(__start_initialization_multiplatform) | |||
1656 | bl .__mmu_off | 1695 | bl .__mmu_off |
1657 | b .__after_prom_start | 1696 | b .__after_prom_start |
1658 | 1697 | ||
1659 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1660 | _STATIC(__boot_from_prom) | 1698 | _STATIC(__boot_from_prom) |
1661 | /* Save parameters */ | 1699 | /* Save parameters */ |
1662 | mr r31,r3 | 1700 | mr r31,r3 |
@@ -1696,7 +1734,6 @@ _STATIC(__boot_from_prom) | |||
1696 | bl .prom_init | 1734 | bl .prom_init |
1697 | /* We never return */ | 1735 | /* We never return */ |
1698 | trap | 1736 | trap |
1699 | #endif | ||
1700 | 1737 | ||
1701 | /* | 1738 | /* |
1702 | * At this point, r3 contains the physical address we are running at, | 1739 | * At this point, r3 contains the physical address we are running at, |
@@ -1752,8 +1789,6 @@ _STATIC(__after_prom_start) | |||
1752 | bl .copy_and_flush /* copy the rest */ | 1789 | bl .copy_and_flush /* copy the rest */ |
1753 | b .start_here_multiplatform | 1790 | b .start_here_multiplatform |
1754 | 1791 | ||
1755 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
1756 | |||
1757 | /* | 1792 | /* |
1758 | * Copy routine used to copy the kernel to start at physical address 0 | 1793 | * Copy routine used to copy the kernel to start at physical address 0 |
1759 | * and flush and invalidate the caches as needed. | 1794 | * and flush and invalidate the caches as needed. |
@@ -1836,7 +1871,7 @@ _GLOBAL(pmac_secondary_start) | |||
1836 | ld r1,PACAEMERGSP(r13) | 1871 | ld r1,PACAEMERGSP(r13) |
1837 | subi r1,r1,STACK_FRAME_OVERHEAD | 1872 | subi r1,r1,STACK_FRAME_OVERHEAD |
1838 | 1873 | ||
1839 | b .__secondary_start | 1874 | b __secondary_start |
1840 | 1875 | ||
1841 | #endif /* CONFIG_PPC_PMAC */ | 1876 | #endif /* CONFIG_PPC_PMAC */ |
1842 | 1877 | ||
@@ -1853,7 +1888,7 @@ _GLOBAL(pmac_secondary_start) | |||
1853 | * r13 = paca virtual address | 1888 | * r13 = paca virtual address |
1854 | * SPRG3 = paca virtual address | 1889 | * SPRG3 = paca virtual address |
1855 | */ | 1890 | */ |
1856 | _GLOBAL(__secondary_start) | 1891 | __secondary_start: |
1857 | /* Set thread priority to MEDIUM */ | 1892 | /* Set thread priority to MEDIUM */ |
1858 | HMT_MEDIUM | 1893 | HMT_MEDIUM |
1859 | 1894 | ||
@@ -1877,11 +1912,16 @@ _GLOBAL(__secondary_start) | |||
1877 | /* enable MMU and jump to start_secondary */ | 1912 | /* enable MMU and jump to start_secondary */ |
1878 | LOAD_REG_ADDR(r3, .start_secondary_prolog) | 1913 | LOAD_REG_ADDR(r3, .start_secondary_prolog) |
1879 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) | 1914 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) |
1880 | #ifdef DO_SOFT_DISABLE | 1915 | #ifdef CONFIG_PPC_ISERIES |
1881 | BEGIN_FW_FTR_SECTION | 1916 | BEGIN_FW_FTR_SECTION |
1882 | ori r4,r4,MSR_EE | 1917 | ori r4,r4,MSR_EE |
1883 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 1918 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
1884 | #endif | 1919 | #endif |
1920 | BEGIN_FW_FTR_SECTION | ||
1921 | stb r7,PACASOFTIRQEN(r13) | ||
1922 | stb r7,PACAHARDIRQEN(r13) | ||
1923 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
1924 | |||
1885 | mtspr SPRN_SRR0,r3 | 1925 | mtspr SPRN_SRR0,r3 |
1886 | mtspr SPRN_SRR1,r4 | 1926 | mtspr SPRN_SRR1,r4 |
1887 | rfid | 1927 | rfid |
@@ -1913,7 +1953,6 @@ _GLOBAL(enable_64b_mode) | |||
1913 | isync | 1953 | isync |
1914 | blr | 1954 | blr |
1915 | 1955 | ||
1916 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1917 | /* | 1956 | /* |
1918 | * This is where the main kernel code starts. | 1957 | * This is where the main kernel code starts. |
1919 | */ | 1958 | */ |
@@ -1964,13 +2003,6 @@ _STATIC(start_here_multiplatform) | |||
1964 | addi r2,r2,0x4000 | 2003 | addi r2,r2,0x4000 |
1965 | add r2,r2,r26 | 2004 | add r2,r2,r26 |
1966 | 2005 | ||
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, | 2006 | /* Do very early kernel initializations, including initial hash table, |
1975 | * stab and slb setup before we turn on relocation. */ | 2007 | * stab and slb setup before we turn on relocation. */ |
1976 | 2008 | ||
@@ -1984,7 +2016,6 @@ _STATIC(start_here_multiplatform) | |||
1984 | mtspr SPRN_SRR1,r4 | 2016 | mtspr SPRN_SRR1,r4 |
1985 | rfid | 2017 | rfid |
1986 | b . /* prevent speculative execution */ | 2018 | b . /* prevent speculative execution */ |
1987 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
1988 | 2019 | ||
1989 | /* This is where all platforms converge execution */ | 2020 | /* This is where all platforms converge execution */ |
1990 | _STATIC(start_here_common) | 2021 | _STATIC(start_here_common) |
@@ -2000,13 +2031,6 @@ _STATIC(start_here_common) | |||
2000 | li r0,0 | 2031 | li r0,0 |
2001 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | 2032 | stdu r0,-STACK_FRAME_OVERHEAD(r1) |
2002 | 2033 | ||
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 */ | 2034 | /* ptr to current */ |
2011 | LOAD_REG_IMMEDIATE(r4, init_task) | 2035 | LOAD_REG_IMMEDIATE(r4, init_task) |
2012 | std r4,PACACURRENT(r13) | 2036 | std r4,PACACURRENT(r13) |
@@ -2019,15 +2043,18 @@ _STATIC(start_here_common) | |||
2019 | 2043 | ||
2020 | /* Load up the kernel context */ | 2044 | /* Load up the kernel context */ |
2021 | 5: | 2045 | 5: |
2022 | #ifdef DO_SOFT_DISABLE | ||
2023 | BEGIN_FW_FTR_SECTION | ||
2024 | li r5,0 | 2046 | li r5,0 |
2025 | stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ | 2047 | stb r5,PACASOFTIRQEN(r13) /* Soft Disabled */ |
2048 | #ifdef CONFIG_PPC_ISERIES | ||
2049 | BEGIN_FW_FTR_SECTION | ||
2026 | mfmsr r5 | 2050 | mfmsr r5 |
2027 | ori r5,r5,MSR_EE /* Hard Enabled */ | 2051 | ori r5,r5,MSR_EE /* Hard Enabled */ |
2028 | mtmsrd r5 | 2052 | mtmsrd r5 |
2029 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 2053 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
2030 | #endif | 2054 | #endif |
2055 | BEGIN_FW_FTR_SECTION | ||
2056 | stb r5,PACAHARDIRQEN(r13) | ||
2057 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
2031 | 2058 | ||
2032 | bl .start_kernel | 2059 | bl .start_kernel |
2033 | 2060 | ||
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 39db7a3affe1..82bd2f10770f 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c | |||
@@ -112,7 +112,7 @@ static int ibmebus_dma_supported(struct device *dev, u64 mask) | |||
112 | return 1; | 112 | return 1; |
113 | } | 113 | } |
114 | 114 | ||
115 | struct dma_mapping_ops ibmebus_dma_ops = { | 115 | static struct dma_mapping_ops ibmebus_dma_ops = { |
116 | .alloc_coherent = ibmebus_alloc_coherent, | 116 | .alloc_coherent = ibmebus_alloc_coherent, |
117 | .free_coherent = ibmebus_free_coherent, | 117 | .free_coherent = ibmebus_free_coherent, |
118 | .map_single = ibmebus_map_single, | 118 | .map_single = ibmebus_map_single, |
@@ -176,6 +176,10 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_common( | |||
176 | dev->ofdev.dev.bus = &ibmebus_bus_type; | 176 | dev->ofdev.dev.bus = &ibmebus_bus_type; |
177 | dev->ofdev.dev.release = ibmebus_dev_release; | 177 | dev->ofdev.dev.release = ibmebus_dev_release; |
178 | 178 | ||
179 | dev->ofdev.dev.archdata.of_node = dev->ofdev.node; | ||
180 | dev->ofdev.dev.archdata.dma_ops = &ibmebus_dma_ops; | ||
181 | dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node); | ||
182 | |||
179 | /* An ibmebusdev is based on a of_device. We have to change the | 183 | /* An ibmebusdev is based on a of_device. We have to change the |
180 | * bus type to use our own DMA mapping operations. | 184 | * bus type to use our own DMA mapping operations. |
181 | */ | 185 | */ |
@@ -210,11 +214,10 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node( | |||
210 | return NULL; | 214 | return NULL; |
211 | } | 215 | } |
212 | 216 | ||
213 | dev = kmalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); | 217 | dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); |
214 | if (!dev) { | 218 | if (!dev) { |
215 | return NULL; | 219 | return NULL; |
216 | } | 220 | } |
217 | memset(dev, 0, sizeof(struct ibmebus_dev)); | ||
218 | 221 | ||
219 | dev->ofdev.node = of_node_get(dn); | 222 | dev->ofdev.node = of_node_get(dn); |
220 | 223 | ||
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 4180c3998b39..8994af327b47 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c | |||
@@ -39,6 +39,13 @@ | |||
39 | #define cpu_should_die() 0 | 39 | #define cpu_should_die() 0 |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | static int __init powersave_off(char *arg) | ||
43 | { | ||
44 | ppc_md.power_save = NULL; | ||
45 | return 0; | ||
46 | } | ||
47 | __setup("powersave=off", powersave_off); | ||
48 | |||
42 | /* | 49 | /* |
43 | * The body of the idle task. | 50 | * The body of the idle task. |
44 | */ | 51 | */ |
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index 30de81da7b40..ba3195478600 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S | |||
@@ -30,6 +30,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) | |||
30 | beqlr | 30 | beqlr |
31 | 31 | ||
32 | /* Go to NAP now */ | 32 | /* Go to NAP now */ |
33 | mfmsr r7 | ||
34 | rldicl r0,r7,48,1 | ||
35 | rotldi r0,r0,16 | ||
36 | mtmsrd r0,1 /* hard-disable interrupts */ | ||
37 | li r0,1 | ||
38 | stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ | ||
39 | stb r0,PACAHARDIRQEN(r13) | ||
33 | BEGIN_FTR_SECTION | 40 | BEGIN_FTR_SECTION |
34 | DSSALL | 41 | DSSALL |
35 | sync | 42 | sync |
@@ -38,7 +45,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | |||
38 | ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ | 45 | ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ |
39 | ori r8,r8,_TLF_NAPPING /* so when we take an exception */ | 46 | ori r8,r8,_TLF_NAPPING /* so when we take an exception */ |
40 | std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ | 47 | std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ |
41 | mfmsr r7 | ||
42 | ori r7,r7,MSR_EE | 48 | ori r7,r7,MSR_EE |
43 | oris r7,r7,MSR_POW@h | 49 | oris r7,r7,MSR_POW@h |
44 | 1: sync | 50 | 1: sync |
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c index e98180686b35..34ae11494ddc 100644 --- a/arch/powerpc/kernel/io.c +++ b/arch/powerpc/kernel/io.c | |||
@@ -25,13 +25,11 @@ | |||
25 | #include <asm/firmware.h> | 25 | #include <asm/firmware.h> |
26 | #include <asm/bug.h> | 26 | #include <asm/bug.h> |
27 | 27 | ||
28 | void _insb(volatile u8 __iomem *port, void *buf, long count) | 28 | void _insb(const volatile u8 __iomem *port, void *buf, long count) |
29 | { | 29 | { |
30 | u8 *tbuf = buf; | 30 | u8 *tbuf = buf; |
31 | u8 tmp; | 31 | u8 tmp; |
32 | 32 | ||
33 | BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES)); | ||
34 | |||
35 | if (unlikely(count <= 0)) | 33 | if (unlikely(count <= 0)) |
36 | return; | 34 | return; |
37 | asm volatile("sync"); | 35 | asm volatile("sync"); |
@@ -48,8 +46,6 @@ void _outsb(volatile u8 __iomem *port, const void *buf, long count) | |||
48 | { | 46 | { |
49 | const u8 *tbuf = buf; | 47 | const u8 *tbuf = buf; |
50 | 48 | ||
51 | BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES)); | ||
52 | |||
53 | if (unlikely(count <= 0)) | 49 | if (unlikely(count <= 0)) |
54 | return; | 50 | return; |
55 | asm volatile("sync"); | 51 | asm volatile("sync"); |
@@ -60,13 +56,11 @@ void _outsb(volatile u8 __iomem *port, const void *buf, long count) | |||
60 | } | 56 | } |
61 | EXPORT_SYMBOL(_outsb); | 57 | EXPORT_SYMBOL(_outsb); |
62 | 58 | ||
63 | void _insw_ns(volatile u16 __iomem *port, void *buf, long count) | 59 | void _insw_ns(const volatile u16 __iomem *port, void *buf, long count) |
64 | { | 60 | { |
65 | u16 *tbuf = buf; | 61 | u16 *tbuf = buf; |
66 | u16 tmp; | 62 | u16 tmp; |
67 | 63 | ||
68 | BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES)); | ||
69 | |||
70 | if (unlikely(count <= 0)) | 64 | if (unlikely(count <= 0)) |
71 | return; | 65 | return; |
72 | asm volatile("sync"); | 66 | asm volatile("sync"); |
@@ -83,8 +77,6 @@ void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count) | |||
83 | { | 77 | { |
84 | const u16 *tbuf = buf; | 78 | const u16 *tbuf = buf; |
85 | 79 | ||
86 | BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES)); | ||
87 | |||
88 | if (unlikely(count <= 0)) | 80 | if (unlikely(count <= 0)) |
89 | return; | 81 | return; |
90 | asm volatile("sync"); | 82 | asm volatile("sync"); |
@@ -95,13 +87,11 @@ void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count) | |||
95 | } | 87 | } |
96 | EXPORT_SYMBOL(_outsw_ns); | 88 | EXPORT_SYMBOL(_outsw_ns); |
97 | 89 | ||
98 | void _insl_ns(volatile u32 __iomem *port, void *buf, long count) | 90 | void _insl_ns(const volatile u32 __iomem *port, void *buf, long count) |
99 | { | 91 | { |
100 | u32 *tbuf = buf; | 92 | u32 *tbuf = buf; |
101 | u32 tmp; | 93 | u32 tmp; |
102 | 94 | ||
103 | BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES)); | ||
104 | |||
105 | if (unlikely(count <= 0)) | 95 | if (unlikely(count <= 0)) |
106 | return; | 96 | return; |
107 | asm volatile("sync"); | 97 | asm volatile("sync"); |
@@ -118,8 +108,6 @@ void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count) | |||
118 | { | 108 | { |
119 | const u32 *tbuf = buf; | 109 | const u32 *tbuf = buf; |
120 | 110 | ||
121 | BUG_ON(firmware_has_feature(FW_FEATURE_ISERIES)); | ||
122 | |||
123 | if (unlikely(count <= 0)) | 111 | if (unlikely(count <= 0)) |
124 | return; | 112 | return; |
125 | asm volatile("sync"); | 113 | asm volatile("sync"); |
@@ -129,3 +117,90 @@ void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count) | |||
129 | asm volatile("sync"); | 117 | asm volatile("sync"); |
130 | } | 118 | } |
131 | EXPORT_SYMBOL(_outsl_ns); | 119 | EXPORT_SYMBOL(_outsl_ns); |
120 | |||
121 | #define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0) | ||
122 | |||
123 | void _memset_io(volatile void __iomem *addr, int c, unsigned long n) | ||
124 | { | ||
125 | void *p = (void __force *)addr; | ||
126 | u32 lc = c; | ||
127 | lc |= lc << 8; | ||
128 | lc |= lc << 16; | ||
129 | |||
130 | __asm__ __volatile__ ("sync" : : : "memory"); | ||
131 | while(n && !IO_CHECK_ALIGN(p, 4)) { | ||
132 | *((volatile u8 *)p) = c; | ||
133 | p++; | ||
134 | n--; | ||
135 | } | ||
136 | while(n >= 4) { | ||
137 | *((volatile u32 *)p) = lc; | ||
138 | p += 4; | ||
139 | n -= 4; | ||
140 | } | ||
141 | while(n) { | ||
142 | *((volatile u8 *)p) = c; | ||
143 | p++; | ||
144 | n--; | ||
145 | } | ||
146 | __asm__ __volatile__ ("sync" : : : "memory"); | ||
147 | } | ||
148 | EXPORT_SYMBOL(_memset_io); | ||
149 | |||
150 | void _memcpy_fromio(void *dest, const volatile void __iomem *src, | ||
151 | unsigned long n) | ||
152 | { | ||
153 | void *vsrc = (void __force *) src; | ||
154 | |||
155 | __asm__ __volatile__ ("sync" : : : "memory"); | ||
156 | while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) { | ||
157 | *((u8 *)dest) = *((volatile u8 *)vsrc); | ||
158 | __asm__ __volatile__ ("eieio" : : : "memory"); | ||
159 | vsrc++; | ||
160 | dest++; | ||
161 | n--; | ||
162 | } | ||
163 | while(n > 4) { | ||
164 | *((u32 *)dest) = *((volatile u32 *)vsrc); | ||
165 | __asm__ __volatile__ ("eieio" : : : "memory"); | ||
166 | vsrc += 4; | ||
167 | dest += 4; | ||
168 | n -= 4; | ||
169 | } | ||
170 | while(n) { | ||
171 | *((u8 *)dest) = *((volatile u8 *)vsrc); | ||
172 | __asm__ __volatile__ ("eieio" : : : "memory"); | ||
173 | vsrc++; | ||
174 | dest++; | ||
175 | n--; | ||
176 | } | ||
177 | __asm__ __volatile__ ("sync" : : : "memory"); | ||
178 | } | ||
179 | EXPORT_SYMBOL(_memcpy_fromio); | ||
180 | |||
181 | void _memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n) | ||
182 | { | ||
183 | void *vdest = (void __force *) dest; | ||
184 | |||
185 | __asm__ __volatile__ ("sync" : : : "memory"); | ||
186 | while(n && (!IO_CHECK_ALIGN(vdest, 4) || !IO_CHECK_ALIGN(src, 4))) { | ||
187 | *((volatile u8 *)vdest) = *((u8 *)src); | ||
188 | src++; | ||
189 | vdest++; | ||
190 | n--; | ||
191 | } | ||
192 | while(n > 4) { | ||
193 | *((volatile u32 *)vdest) = *((volatile u32 *)src); | ||
194 | src += 4; | ||
195 | vdest += 4; | ||
196 | n-=4; | ||
197 | } | ||
198 | while(n) { | ||
199 | *((volatile u8 *)vdest) = *((u8 *)src); | ||
200 | src++; | ||
201 | vdest++; | ||
202 | n--; | ||
203 | } | ||
204 | __asm__ __volatile__ ("sync" : : : "memory"); | ||
205 | } | ||
206 | EXPORT_SYMBOL(_memcpy_toio); | ||
diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c index a13a93dfc655..c68113371050 100644 --- a/arch/powerpc/kernel/iomap.c +++ b/arch/powerpc/kernel/iomap.c | |||
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(iowrite32_rep); | |||
106 | 106 | ||
107 | void __iomem *ioport_map(unsigned long port, unsigned int len) | 107 | void __iomem *ioport_map(unsigned long port, unsigned int len) |
108 | { | 108 | { |
109 | return (void __iomem *) (port+pci_io_base); | 109 | return (void __iomem *) (port + _IO_BASE); |
110 | } | 110 | } |
111 | 111 | ||
112 | void ioport_unmap(void __iomem *addr) | 112 | void ioport_unmap(void __iomem *addr) |
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index f88a2a675d90..95edad4faf26 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) || |
@@ -247,9 +258,9 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
247 | spin_unlock_irqrestore(&(tbl->it_lock), flags); | 258 | spin_unlock_irqrestore(&(tbl->it_lock), flags); |
248 | } | 259 | } |
249 | 260 | ||
250 | int iommu_map_sg(struct device *dev, struct iommu_table *tbl, | 261 | int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, |
251 | struct scatterlist *sglist, int nelems, | 262 | int nelems, unsigned long mask, |
252 | unsigned long mask, enum dma_data_direction direction) | 263 | enum dma_data_direction direction) |
253 | { | 264 | { |
254 | dma_addr_t dma_next = 0, dma_addr; | 265 | dma_addr_t dma_next = 0, dma_addr; |
255 | unsigned long flags; | 266 | unsigned long flags; |
@@ -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/irq.c b/arch/powerpc/kernel/irq.c index 5e37bf14ef2d..0bd8c7665834 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -64,8 +64,9 @@ | |||
64 | #include <asm/ptrace.h> | 64 | #include <asm/ptrace.h> |
65 | #include <asm/machdep.h> | 65 | #include <asm/machdep.h> |
66 | #include <asm/udbg.h> | 66 | #include <asm/udbg.h> |
67 | #ifdef CONFIG_PPC_ISERIES | 67 | #ifdef CONFIG_PPC64 |
68 | #include <asm/paca.h> | 68 | #include <asm/paca.h> |
69 | #include <asm/firmware.h> | ||
69 | #endif | 70 | #endif |
70 | 71 | ||
71 | int __irq_offset_value; | 72 | int __irq_offset_value; |
@@ -95,6 +96,74 @@ extern atomic_t ipi_sent; | |||
95 | EXPORT_SYMBOL(irq_desc); | 96 | EXPORT_SYMBOL(irq_desc); |
96 | 97 | ||
97 | int distribute_irqs = 1; | 98 | int distribute_irqs = 1; |
99 | |||
100 | static inline unsigned long get_hard_enabled(void) | ||
101 | { | ||
102 | unsigned long enabled; | ||
103 | |||
104 | __asm__ __volatile__("lbz %0,%1(13)" | ||
105 | : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled))); | ||
106 | |||
107 | return enabled; | ||
108 | } | ||
109 | |||
110 | static inline void set_soft_enabled(unsigned long enable) | ||
111 | { | ||
112 | __asm__ __volatile__("stb %0,%1(13)" | ||
113 | : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); | ||
114 | } | ||
115 | |||
116 | void local_irq_restore(unsigned long en) | ||
117 | { | ||
118 | /* | ||
119 | * get_paca()->soft_enabled = en; | ||
120 | * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1? | ||
121 | * That was allowed before, and in such a case we do need to take care | ||
122 | * that gcc will set soft_enabled directly via r13, not choose to use | ||
123 | * an intermediate register, lest we're preempted to a different cpu. | ||
124 | */ | ||
125 | set_soft_enabled(en); | ||
126 | if (!en) | ||
127 | return; | ||
128 | |||
129 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
130 | /* | ||
131 | * Do we need to disable preemption here? Not really: in the | ||
132 | * unlikely event that we're preempted to a different cpu in | ||
133 | * between getting r13, loading its lppaca_ptr, and loading | ||
134 | * its any_int, we might call iseries_handle_interrupts without | ||
135 | * an interrupt pending on the new cpu, but that's no disaster, | ||
136 | * is it? And the business of preempting us off the old cpu | ||
137 | * would itself involve a local_irq_restore which handles the | ||
138 | * interrupt to that cpu. | ||
139 | * | ||
140 | * But use "local_paca->lppaca_ptr" instead of "get_lppaca()" | ||
141 | * to avoid any preemption checking added into get_paca(). | ||
142 | */ | ||
143 | if (local_paca->lppaca_ptr->int_dword.any_int) | ||
144 | iseries_handle_interrupts(); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * if (get_paca()->hard_enabled) return; | ||
150 | * But again we need to take care that gcc gets hard_enabled directly | ||
151 | * via r13, not choose to use an intermediate register, lest we're | ||
152 | * preempted to a different cpu in between the two instructions. | ||
153 | */ | ||
154 | if (get_hard_enabled()) | ||
155 | return; | ||
156 | |||
157 | /* | ||
158 | * Need to hard-enable interrupts here. Since currently disabled, | ||
159 | * no need to take further asm precautions against preemption; but | ||
160 | * use local_paca instead of get_paca() to avoid preemption checking. | ||
161 | */ | ||
162 | local_paca->hard_enabled = en; | ||
163 | if ((int)mfspr(SPRN_DEC) < 0) | ||
164 | mtspr(SPRN_DEC, 1); | ||
165 | hard_irq_enable(); | ||
166 | } | ||
98 | #endif /* CONFIG_PPC64 */ | 167 | #endif /* CONFIG_PPC64 */ |
99 | 168 | ||
100 | int show_interrupts(struct seq_file *p, void *v) | 169 | int show_interrupts(struct seq_file *p, void *v) |
@@ -246,7 +315,8 @@ void do_IRQ(struct pt_regs *regs) | |||
246 | set_irq_regs(old_regs); | 315 | set_irq_regs(old_regs); |
247 | 316 | ||
248 | #ifdef CONFIG_PPC_ISERIES | 317 | #ifdef CONFIG_PPC_ISERIES |
249 | if (get_lppaca()->int_dword.fields.decr_int) { | 318 | if (firmware_has_feature(FW_FEATURE_ISERIES) && |
319 | get_lppaca()->int_dword.fields.decr_int) { | ||
250 | get_lppaca()->int_dword.fields.decr_int = 0; | 320 | get_lppaca()->int_dword.fields.decr_int = 0; |
251 | /* Signal a fake decrementer interrupt */ | 321 | /* Signal a fake decrementer interrupt */ |
252 | timer_interrupt(regs); | 322 | timer_interrupt(regs); |
@@ -626,10 +696,14 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); | |||
626 | 696 | ||
627 | void irq_dispose_mapping(unsigned int virq) | 697 | void irq_dispose_mapping(unsigned int virq) |
628 | { | 698 | { |
629 | struct irq_host *host = irq_map[virq].host; | 699 | struct irq_host *host; |
630 | irq_hw_number_t hwirq; | 700 | irq_hw_number_t hwirq; |
631 | unsigned long flags; | 701 | unsigned long flags; |
632 | 702 | ||
703 | if (virq == NO_IRQ) | ||
704 | return; | ||
705 | |||
706 | host = irq_map[virq].host; | ||
633 | WARN_ON (host == NULL); | 707 | WARN_ON (host == NULL); |
634 | if (host == NULL) | 708 | if (host == NULL) |
635 | return; | 709 | return; |
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index 7b8d12b9026c..4657563f8813 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c | |||
@@ -85,7 +85,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) | |||
85 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 85 | void __kprobes arch_remove_kprobe(struct kprobe *p) |
86 | { | 86 | { |
87 | mutex_lock(&kprobe_mutex); | 87 | mutex_lock(&kprobe_mutex); |
88 | free_insn_slot(p->ainsn.insn); | 88 | free_insn_slot(p->ainsn.insn, 0); |
89 | mutex_unlock(&kprobe_mutex); | 89 | mutex_unlock(&kprobe_mutex); |
90 | } | 90 | } |
91 | 91 | ||
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..8339fd609de0 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/cache.h> | 25 | #include <linux/cache.h> |
26 | #include <linux/bug.h> | ||
27 | |||
28 | #include "setup.h" | ||
26 | 29 | ||
27 | #if 0 | 30 | #if 0 |
28 | #define DEBUGP printk | 31 | #define DEBUGP printk |
@@ -269,39 +272,44 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, | |||
269 | return 0; | 272 | return 0; |
270 | } | 273 | } |
271 | 274 | ||
272 | int module_finalize(const Elf_Ehdr *hdr, | 275 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, |
273 | const Elf_Shdr *sechdrs, | 276 | const Elf_Shdr *sechdrs, |
274 | struct module *me) | 277 | const char *name) |
275 | { | 278 | { |
276 | char *secstrings; | 279 | char *secstrings; |
277 | unsigned int i; | 280 | unsigned int i; |
278 | 281 | ||
279 | me->arch.bug_table = NULL; | ||
280 | me->arch.num_bugs = 0; | ||
281 | |||
282 | /* Find the __bug_table section, if present */ | ||
283 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 282 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
284 | for (i = 1; i < hdr->e_shnum; i++) { | 283 | for (i = 1; i < hdr->e_shnum; i++) |
285 | if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) | 284 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) |
286 | continue; | 285 | return &sechdrs[i]; |
287 | me->arch.bug_table = (void *) sechdrs[i].sh_addr; | 286 | return NULL; |
288 | me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); | 287 | } |
289 | break; | 288 | |
290 | } | 289 | int module_finalize(const Elf_Ehdr *hdr, |
290 | const Elf_Shdr *sechdrs, | ||
291 | struct module *me) | ||
292 | { | ||
293 | const Elf_Shdr *sect; | ||
294 | int err; | ||
295 | |||
296 | err = module_bug_finalize(hdr, sechdrs, me); | ||
297 | if (err) /* never true, currently */ | ||
298 | return err; | ||
291 | 299 | ||
292 | /* | 300 | /* Apply feature fixups */ |
293 | * Strictly speaking this should have a spinlock to protect against | 301 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); |
294 | * traversals, but since we only traverse on BUG()s, a spinlock | 302 | if (sect != NULL) |
295 | * could potentially lead to deadlock and thus be counter-productive. | 303 | do_feature_fixups(cur_cpu_spec->cpu_features, |
296 | */ | 304 | (void *)sect->sh_addr, |
297 | list_add(&me->arch.bug_list, &module_bug_list); | 305 | (void *)sect->sh_addr + sect->sh_size); |
298 | 306 | ||
299 | return 0; | 307 | return 0; |
300 | } | 308 | } |
301 | 309 | ||
302 | void module_arch_cleanup(struct module *mod) | 310 | void module_arch_cleanup(struct module *mod) |
303 | { | 311 | { |
304 | list_del(&mod->arch.bug_list); | 312 | module_bug_cleanup(mod); |
305 | } | 313 | } |
306 | 314 | ||
307 | struct bug_entry *module_find_bug(unsigned long bugaddr) | 315 | struct bug_entry *module_find_bug(unsigned long bugaddr) |
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index ba34001fca8e..75c7c4f19280 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c | |||
@@ -20,8 +20,12 @@ | |||
20 | #include <linux/moduleloader.h> | 20 | #include <linux/moduleloader.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
23 | #include <linux/bug.h> | ||
23 | #include <asm/module.h> | 24 | #include <asm/module.h> |
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
26 | #include <asm/firmware.h> | ||
27 | |||
28 | #include "setup.h" | ||
25 | 29 | ||
26 | /* FIXME: We don't do .init separately. To do this, we'd need to have | 30 | /* 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 | 31 | a separate r2 value in the init and core section, and stub between |
@@ -400,6 +404,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
400 | | (value & 0x03fffffc); | 404 | | (value & 0x03fffffc); |
401 | break; | 405 | break; |
402 | 406 | ||
407 | case R_PPC64_REL64: | ||
408 | /* 64 bits relative (used by features fixups) */ | ||
409 | *location = value - (unsigned long)location; | ||
410 | break; | ||
411 | |||
403 | default: | 412 | default: |
404 | printk("%s: Unknown ADD relocation: %lu\n", | 413 | printk("%s: Unknown ADD relocation: %lu\n", |
405 | me->name, | 414 | me->name, |
@@ -413,38 +422,49 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
413 | 422 | ||
414 | LIST_HEAD(module_bug_list); | 423 | LIST_HEAD(module_bug_list); |
415 | 424 | ||
416 | int module_finalize(const Elf_Ehdr *hdr, | 425 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, |
417 | const Elf_Shdr *sechdrs, struct module *me) | 426 | const Elf_Shdr *sechdrs, |
427 | const char *name) | ||
418 | { | 428 | { |
419 | char *secstrings; | 429 | char *secstrings; |
420 | unsigned int i; | 430 | unsigned int i; |
421 | 431 | ||
422 | me->arch.bug_table = NULL; | ||
423 | me->arch.num_bugs = 0; | ||
424 | |||
425 | /* Find the __bug_table section, if present */ | ||
426 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 432 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
427 | for (i = 1; i < hdr->e_shnum; i++) { | 433 | for (i = 1; i < hdr->e_shnum; i++) |
428 | if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) | 434 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) |
429 | continue; | 435 | return &sechdrs[i]; |
430 | me->arch.bug_table = (void *) sechdrs[i].sh_addr; | 436 | return NULL; |
431 | me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); | 437 | } |
432 | break; | ||
433 | } | ||
434 | 438 | ||
435 | /* | 439 | int module_finalize(const Elf_Ehdr *hdr, |
436 | * Strictly speaking this should have a spinlock to protect against | 440 | const Elf_Shdr *sechdrs, struct module *me) |
437 | * traversals, but since we only traverse on BUG()s, a spinlock | 441 | { |
438 | * could potentially lead to deadlock and thus be counter-productive. | 442 | const Elf_Shdr *sect; |
439 | */ | 443 | int err; |
440 | list_add(&me->arch.bug_list, &module_bug_list); | 444 | |
445 | err = module_bug_finalize(hdr, sechdrs, me); | ||
446 | if (err) | ||
447 | return err; | ||
448 | |||
449 | /* Apply feature fixups */ | ||
450 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | ||
451 | if (sect != NULL) | ||
452 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
453 | (void *)sect->sh_addr, | ||
454 | (void *)sect->sh_addr + sect->sh_size); | ||
455 | |||
456 | sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); | ||
457 | if (sect != NULL) | ||
458 | do_feature_fixups(powerpc_firmware_features, | ||
459 | (void *)sect->sh_addr, | ||
460 | (void *)sect->sh_addr + sect->sh_size); | ||
441 | 461 | ||
442 | return 0; | 462 | return 0; |
443 | } | 463 | } |
444 | 464 | ||
445 | void module_arch_cleanup(struct module *mod) | 465 | void module_arch_cleanup(struct module *mod) |
446 | { | 466 | { |
447 | list_del(&mod->arch.bug_list); | 467 | module_bug_cleanup(mod); |
448 | } | 468 | } |
449 | 469 | ||
450 | struct bug_entry *module_find_bug(unsigned long bugaddr) | 470 | struct bug_entry *module_find_bug(unsigned long bugaddr) |
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 397c83eda20e..e921514e655b 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c | |||
@@ -9,30 +9,26 @@ | |||
9 | #include <asm/of_device.h> | 9 | #include <asm/of_device.h> |
10 | 10 | ||
11 | /** | 11 | /** |
12 | * of_match_device - Tell if an of_device structure has a matching | 12 | * of_match_node - Tell if an device_node has a matching of_match structure |
13 | * of_match structure | ||
14 | * @ids: array of of device match structures to search in | 13 | * @ids: array of of device match structures to search in |
15 | * @dev: the of device structure to match against | 14 | * @node: the of device structure to match against |
16 | * | 15 | * |
17 | * Used by a driver to check whether an of_device present in the | 16 | * Low level utility function used by device matching. |
18 | * system is in its list of supported devices. | ||
19 | */ | 17 | */ |
20 | const struct of_device_id *of_match_device(const struct of_device_id *matches, | 18 | const struct of_device_id *of_match_node(const struct of_device_id *matches, |
21 | const struct of_device *dev) | 19 | const struct device_node *node) |
22 | { | 20 | { |
23 | if (!dev->node) | ||
24 | return NULL; | ||
25 | while (matches->name[0] || matches->type[0] || matches->compatible[0]) { | 21 | while (matches->name[0] || matches->type[0] || matches->compatible[0]) { |
26 | int match = 1; | 22 | int match = 1; |
27 | if (matches->name[0]) | 23 | if (matches->name[0]) |
28 | match &= dev->node->name | 24 | match &= node->name |
29 | && !strcmp(matches->name, dev->node->name); | 25 | && !strcmp(matches->name, node->name); |
30 | if (matches->type[0]) | 26 | if (matches->type[0]) |
31 | match &= dev->node->type | 27 | match &= node->type |
32 | && !strcmp(matches->type, dev->node->type); | 28 | && !strcmp(matches->type, node->type); |
33 | if (matches->compatible[0]) | 29 | if (matches->compatible[0]) |
34 | match &= device_is_compatible(dev->node, | 30 | match &= device_is_compatible(node, |
35 | matches->compatible); | 31 | matches->compatible); |
36 | if (match) | 32 | if (match) |
37 | return matches; | 33 | return matches; |
38 | matches++; | 34 | matches++; |
@@ -40,16 +36,21 @@ const struct of_device_id *of_match_device(const struct of_device_id *matches, | |||
40 | return NULL; | 36 | return NULL; |
41 | } | 37 | } |
42 | 38 | ||
43 | static int of_platform_bus_match(struct device *dev, struct device_driver *drv) | 39 | /** |
40 | * of_match_device - Tell if an of_device structure has a matching | ||
41 | * of_match structure | ||
42 | * @ids: array of of device match structures to search in | ||
43 | * @dev: the of device structure to match against | ||
44 | * | ||
45 | * Used by a driver to check whether an of_device present in the | ||
46 | * system is in its list of supported devices. | ||
47 | */ | ||
48 | const struct of_device_id *of_match_device(const struct of_device_id *matches, | ||
49 | const struct of_device *dev) | ||
44 | { | 50 | { |
45 | struct of_device * of_dev = to_of_device(dev); | 51 | if (!dev->node) |
46 | struct of_platform_driver * of_drv = to_of_platform_driver(drv); | 52 | return NULL; |
47 | const struct of_device_id * matches = of_drv->match_table; | 53 | return of_match_node(matches, dev->node); |
48 | |||
49 | if (!matches) | ||
50 | return 0; | ||
51 | |||
52 | return of_match_device(matches, of_dev) != NULL; | ||
53 | } | 54 | } |
54 | 55 | ||
55 | struct of_device *of_dev_get(struct of_device *dev) | 56 | struct of_device *of_dev_get(struct of_device *dev) |
@@ -71,96 +72,8 @@ void of_dev_put(struct of_device *dev) | |||
71 | put_device(&dev->dev); | 72 | put_device(&dev->dev); |
72 | } | 73 | } |
73 | 74 | ||
74 | 75 | static ssize_t dev_show_devspec(struct device *dev, | |
75 | static int of_device_probe(struct device *dev) | 76 | struct device_attribute *attr, char *buf) |
76 | { | ||
77 | int error = -ENODEV; | ||
78 | struct of_platform_driver *drv; | ||
79 | struct of_device *of_dev; | ||
80 | const struct of_device_id *match; | ||
81 | |||
82 | drv = to_of_platform_driver(dev->driver); | ||
83 | of_dev = to_of_device(dev); | ||
84 | |||
85 | if (!drv->probe) | ||
86 | return error; | ||
87 | |||
88 | of_dev_get(of_dev); | ||
89 | |||
90 | match = of_match_device(drv->match_table, of_dev); | ||
91 | if (match) | ||
92 | error = drv->probe(of_dev, match); | ||
93 | if (error) | ||
94 | of_dev_put(of_dev); | ||
95 | |||
96 | return error; | ||
97 | } | ||
98 | |||
99 | static int of_device_remove(struct device *dev) | ||
100 | { | ||
101 | struct of_device * of_dev = to_of_device(dev); | ||
102 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | ||
103 | |||
104 | if (dev->driver && drv->remove) | ||
105 | drv->remove(of_dev); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int of_device_suspend(struct device *dev, pm_message_t state) | ||
110 | { | ||
111 | struct of_device * of_dev = to_of_device(dev); | ||
112 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | ||
113 | int error = 0; | ||
114 | |||
115 | if (dev->driver && drv->suspend) | ||
116 | error = drv->suspend(of_dev, state); | ||
117 | return error; | ||
118 | } | ||
119 | |||
120 | static int of_device_resume(struct device * dev) | ||
121 | { | ||
122 | struct of_device * of_dev = to_of_device(dev); | ||
123 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | ||
124 | int error = 0; | ||
125 | |||
126 | if (dev->driver && drv->resume) | ||
127 | error = drv->resume(of_dev); | ||
128 | return error; | ||
129 | } | ||
130 | |||
131 | struct bus_type of_platform_bus_type = { | ||
132 | .name = "of_platform", | ||
133 | .match = of_platform_bus_match, | ||
134 | .probe = of_device_probe, | ||
135 | .remove = of_device_remove, | ||
136 | .suspend = of_device_suspend, | ||
137 | .resume = of_device_resume, | ||
138 | }; | ||
139 | |||
140 | static int __init of_bus_driver_init(void) | ||
141 | { | ||
142 | return bus_register(&of_platform_bus_type); | ||
143 | } | ||
144 | |||
145 | postcore_initcall(of_bus_driver_init); | ||
146 | |||
147 | int of_register_driver(struct of_platform_driver *drv) | ||
148 | { | ||
149 | /* initialize common driver fields */ | ||
150 | drv->driver.name = drv->name; | ||
151 | drv->driver.bus = &of_platform_bus_type; | ||
152 | |||
153 | /* register with core */ | ||
154 | return driver_register(&drv->driver); | ||
155 | } | ||
156 | |||
157 | void of_unregister_driver(struct of_platform_driver *drv) | ||
158 | { | ||
159 | driver_unregister(&drv->driver); | ||
160 | } | ||
161 | |||
162 | |||
163 | static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) | ||
164 | { | 77 | { |
165 | struct of_device *ofdev; | 78 | struct of_device *ofdev; |
166 | 79 | ||
@@ -196,9 +109,7 @@ int of_device_register(struct of_device *ofdev) | |||
196 | if (rc) | 109 | if (rc) |
197 | return rc; | 110 | return rc; |
198 | 111 | ||
199 | device_create_file(&ofdev->dev, &dev_attr_devspec); | 112 | return device_create_file(&ofdev->dev, &dev_attr_devspec); |
200 | |||
201 | return 0; | ||
202 | } | 113 | } |
203 | 114 | ||
204 | void of_device_unregister(struct of_device *ofdev) | 115 | void of_device_unregister(struct of_device *ofdev) |
@@ -208,41 +119,11 @@ void of_device_unregister(struct of_device *ofdev) | |||
208 | device_unregister(&ofdev->dev); | 119 | device_unregister(&ofdev->dev); |
209 | } | 120 | } |
210 | 121 | ||
211 | struct of_device* of_platform_device_create(struct device_node *np, | ||
212 | const char *bus_id, | ||
213 | struct device *parent) | ||
214 | { | ||
215 | struct of_device *dev; | ||
216 | |||
217 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | ||
218 | if (!dev) | ||
219 | return NULL; | ||
220 | memset(dev, 0, sizeof(*dev)); | ||
221 | |||
222 | dev->node = of_node_get(np); | ||
223 | dev->dma_mask = 0xffffffffUL; | ||
224 | dev->dev.dma_mask = &dev->dma_mask; | ||
225 | dev->dev.parent = parent; | ||
226 | dev->dev.bus = &of_platform_bus_type; | ||
227 | dev->dev.release = of_release_dev; | ||
228 | |||
229 | strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); | ||
230 | |||
231 | if (of_device_register(dev) != 0) { | ||
232 | kfree(dev); | ||
233 | return NULL; | ||
234 | } | ||
235 | |||
236 | return dev; | ||
237 | } | ||
238 | 122 | ||
123 | EXPORT_SYMBOL(of_match_node); | ||
239 | EXPORT_SYMBOL(of_match_device); | 124 | EXPORT_SYMBOL(of_match_device); |
240 | EXPORT_SYMBOL(of_platform_bus_type); | ||
241 | EXPORT_SYMBOL(of_register_driver); | ||
242 | EXPORT_SYMBOL(of_unregister_driver); | ||
243 | EXPORT_SYMBOL(of_device_register); | 125 | EXPORT_SYMBOL(of_device_register); |
244 | EXPORT_SYMBOL(of_device_unregister); | 126 | EXPORT_SYMBOL(of_device_unregister); |
245 | EXPORT_SYMBOL(of_dev_get); | 127 | EXPORT_SYMBOL(of_dev_get); |
246 | EXPORT_SYMBOL(of_dev_put); | 128 | EXPORT_SYMBOL(of_dev_put); |
247 | EXPORT_SYMBOL(of_platform_device_create); | ||
248 | EXPORT_SYMBOL(of_release_dev); | 129 | EXPORT_SYMBOL(of_release_dev); |
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c new file mode 100644 index 000000000000..3002ea3a61a2 --- /dev/null +++ b/arch/powerpc/kernel/of_platform.c | |||
@@ -0,0 +1,489 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. | ||
3 | * <benh@kernel.crashing.org> | ||
4 | * and Arnd Bergmann, IBM Corp. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #undef DEBUG | ||
14 | |||
15 | #include <linux/string.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/mod_devicetable.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/pci.h> | ||
22 | |||
23 | #include <asm/errno.h> | ||
24 | #include <asm/dcr.h> | ||
25 | #include <asm/of_device.h> | ||
26 | #include <asm/of_platform.h> | ||
27 | #include <asm/topology.h> | ||
28 | #include <asm/pci-bridge.h> | ||
29 | #include <asm/ppc-pci.h> | ||
30 | #include <asm/atomic.h> | ||
31 | |||
32 | |||
33 | /* | ||
34 | * The list of OF IDs below is used for matching bus types in the | ||
35 | * system whose devices are to be exposed as of_platform_devices. | ||
36 | * | ||
37 | * This is the default list valid for most platforms. This file provides | ||
38 | * functions who can take an explicit list if necessary though | ||
39 | * | ||
40 | * The search is always performed recursively looking for children of | ||
41 | * the provided device_node and recursively if such a children matches | ||
42 | * a bus type in the list | ||
43 | */ | ||
44 | |||
45 | static struct of_device_id of_default_bus_ids[] = { | ||
46 | { .type = "soc", }, | ||
47 | { .compatible = "soc", }, | ||
48 | { .type = "spider", }, | ||
49 | { .type = "axon", }, | ||
50 | { .type = "plb5", }, | ||
51 | { .type = "plb4", }, | ||
52 | { .type = "opb", }, | ||
53 | {}, | ||
54 | }; | ||
55 | |||
56 | static atomic_t bus_no_reg_magic; | ||
57 | |||
58 | /* | ||
59 | * | ||
60 | * OF platform device type definition & base infrastructure | ||
61 | * | ||
62 | */ | ||
63 | |||
64 | static int of_platform_bus_match(struct device *dev, struct device_driver *drv) | ||
65 | { | ||
66 | struct of_device * of_dev = to_of_device(dev); | ||
67 | struct of_platform_driver * of_drv = to_of_platform_driver(drv); | ||
68 | const struct of_device_id * matches = of_drv->match_table; | ||
69 | |||
70 | if (!matches) | ||
71 | return 0; | ||
72 | |||
73 | return of_match_device(matches, of_dev) != NULL; | ||
74 | } | ||
75 | |||
76 | static int of_platform_device_probe(struct device *dev) | ||
77 | { | ||
78 | int error = -ENODEV; | ||
79 | struct of_platform_driver *drv; | ||
80 | struct of_device *of_dev; | ||
81 | const struct of_device_id *match; | ||
82 | |||
83 | drv = to_of_platform_driver(dev->driver); | ||
84 | of_dev = to_of_device(dev); | ||
85 | |||
86 | if (!drv->probe) | ||
87 | return error; | ||
88 | |||
89 | of_dev_get(of_dev); | ||
90 | |||
91 | match = of_match_device(drv->match_table, of_dev); | ||
92 | if (match) | ||
93 | error = drv->probe(of_dev, match); | ||
94 | if (error) | ||
95 | of_dev_put(of_dev); | ||
96 | |||
97 | return error; | ||
98 | } | ||
99 | |||
100 | static int of_platform_device_remove(struct device *dev) | ||
101 | { | ||
102 | struct of_device * of_dev = to_of_device(dev); | ||
103 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | ||
104 | |||
105 | if (dev->driver && drv->remove) | ||
106 | drv->remove(of_dev); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int of_platform_device_suspend(struct device *dev, pm_message_t state) | ||
111 | { | ||
112 | struct of_device * of_dev = to_of_device(dev); | ||
113 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | ||
114 | int error = 0; | ||
115 | |||
116 | if (dev->driver && drv->suspend) | ||
117 | error = drv->suspend(of_dev, state); | ||
118 | return error; | ||
119 | } | ||
120 | |||
121 | static int of_platform_device_resume(struct device * dev) | ||
122 | { | ||
123 | struct of_device * of_dev = to_of_device(dev); | ||
124 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | ||
125 | int error = 0; | ||
126 | |||
127 | if (dev->driver && drv->resume) | ||
128 | error = drv->resume(of_dev); | ||
129 | return error; | ||
130 | } | ||
131 | |||
132 | struct bus_type of_platform_bus_type = { | ||
133 | .name = "of_platform", | ||
134 | .match = of_platform_bus_match, | ||
135 | .probe = of_platform_device_probe, | ||
136 | .remove = of_platform_device_remove, | ||
137 | .suspend = of_platform_device_suspend, | ||
138 | .resume = of_platform_device_resume, | ||
139 | }; | ||
140 | EXPORT_SYMBOL(of_platform_bus_type); | ||
141 | |||
142 | static int __init of_bus_driver_init(void) | ||
143 | { | ||
144 | return bus_register(&of_platform_bus_type); | ||
145 | } | ||
146 | |||
147 | postcore_initcall(of_bus_driver_init); | ||
148 | |||
149 | int of_register_platform_driver(struct of_platform_driver *drv) | ||
150 | { | ||
151 | /* initialize common driver fields */ | ||
152 | drv->driver.name = drv->name; | ||
153 | drv->driver.bus = &of_platform_bus_type; | ||
154 | |||
155 | /* register with core */ | ||
156 | return driver_register(&drv->driver); | ||
157 | } | ||
158 | EXPORT_SYMBOL(of_register_platform_driver); | ||
159 | |||
160 | void of_unregister_platform_driver(struct of_platform_driver *drv) | ||
161 | { | ||
162 | driver_unregister(&drv->driver); | ||
163 | } | ||
164 | EXPORT_SYMBOL(of_unregister_platform_driver); | ||
165 | |||
166 | static void of_platform_make_bus_id(struct of_device *dev) | ||
167 | { | ||
168 | struct device_node *node = dev->node; | ||
169 | char *name = dev->dev.bus_id; | ||
170 | const u32 *reg; | ||
171 | u64 addr; | ||
172 | int magic; | ||
173 | |||
174 | /* | ||
175 | * If it's a DCR based device, use 'd' for native DCRs | ||
176 | * and 'D' for MMIO DCRs. | ||
177 | */ | ||
178 | #ifdef CONFIG_PPC_DCR | ||
179 | reg = get_property(node, "dcr-reg", NULL); | ||
180 | if (reg) { | ||
181 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
182 | snprintf(name, BUS_ID_SIZE, "d%x.%s", | ||
183 | *reg, node->name); | ||
184 | #else /* CONFIG_PPC_DCR_NATIVE */ | ||
185 | addr = of_translate_dcr_address(node, *reg, NULL); | ||
186 | if (addr != OF_BAD_ADDR) { | ||
187 | snprintf(name, BUS_ID_SIZE, | ||
188 | "D%llx.%s", (unsigned long long)addr, | ||
189 | node->name); | ||
190 | return; | ||
191 | } | ||
192 | #endif /* !CONFIG_PPC_DCR_NATIVE */ | ||
193 | } | ||
194 | #endif /* CONFIG_PPC_DCR */ | ||
195 | |||
196 | /* | ||
197 | * For MMIO, get the physical address | ||
198 | */ | ||
199 | reg = get_property(node, "reg", NULL); | ||
200 | if (reg) { | ||
201 | addr = of_translate_address(node, reg); | ||
202 | if (addr != OF_BAD_ADDR) { | ||
203 | snprintf(name, BUS_ID_SIZE, | ||
204 | "%llx.%s", (unsigned long long)addr, | ||
205 | node->name); | ||
206 | return; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * No BusID, use the node name and add a globally incremented | ||
212 | * counter (and pray...) | ||
213 | */ | ||
214 | magic = atomic_add_return(1, &bus_no_reg_magic); | ||
215 | snprintf(name, BUS_ID_SIZE, "%s.%d", node->name, magic - 1); | ||
216 | } | ||
217 | |||
218 | struct of_device* of_platform_device_create(struct device_node *np, | ||
219 | const char *bus_id, | ||
220 | struct device *parent) | ||
221 | { | ||
222 | struct of_device *dev; | ||
223 | |||
224 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | ||
225 | if (!dev) | ||
226 | return NULL; | ||
227 | memset(dev, 0, sizeof(*dev)); | ||
228 | |||
229 | dev->node = of_node_get(np); | ||
230 | dev->dma_mask = 0xffffffffUL; | ||
231 | dev->dev.dma_mask = &dev->dma_mask; | ||
232 | dev->dev.parent = parent; | ||
233 | dev->dev.bus = &of_platform_bus_type; | ||
234 | dev->dev.release = of_release_dev; | ||
235 | dev->dev.archdata.of_node = np; | ||
236 | dev->dev.archdata.numa_node = of_node_to_nid(np); | ||
237 | |||
238 | /* We do not fill the DMA ops for platform devices by default. | ||
239 | * This is currently the responsibility of the platform code | ||
240 | * to do such, possibly using a device notifier | ||
241 | */ | ||
242 | |||
243 | if (bus_id) | ||
244 | strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); | ||
245 | else | ||
246 | of_platform_make_bus_id(dev); | ||
247 | |||
248 | if (of_device_register(dev) != 0) { | ||
249 | kfree(dev); | ||
250 | return NULL; | ||
251 | } | ||
252 | |||
253 | return dev; | ||
254 | } | ||
255 | EXPORT_SYMBOL(of_platform_device_create); | ||
256 | |||
257 | |||
258 | |||
259 | /** | ||
260 | * of_platform_bus_create - Create an OF device for a bus node and all its | ||
261 | * children. Optionally recursively instanciate matching busses. | ||
262 | * @bus: device node of the bus to instanciate | ||
263 | * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to | ||
264 | * disallow recursive creation of child busses | ||
265 | */ | ||
266 | static int of_platform_bus_create(struct device_node *bus, | ||
267 | struct of_device_id *matches, | ||
268 | struct device *parent) | ||
269 | { | ||
270 | struct device_node *child; | ||
271 | struct of_device *dev; | ||
272 | int rc = 0; | ||
273 | |||
274 | for (child = NULL; (child = of_get_next_child(bus, child)); ) { | ||
275 | pr_debug(" create child: %s\n", child->full_name); | ||
276 | dev = of_platform_device_create(child, NULL, parent); | ||
277 | if (dev == NULL) | ||
278 | rc = -ENOMEM; | ||
279 | else if (!of_match_node(matches, child)) | ||
280 | continue; | ||
281 | if (rc == 0) { | ||
282 | pr_debug(" and sub busses\n"); | ||
283 | rc = of_platform_bus_create(child, matches, &dev->dev); | ||
284 | } if (rc) { | ||
285 | of_node_put(child); | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | return rc; | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * of_platform_bus_probe - Probe the device-tree for platform busses | ||
294 | * @root: parent of the first level to probe or NULL for the root of the tree | ||
295 | * @matches: match table, NULL to use the default | ||
296 | * @parent: parent to hook devices from, NULL for toplevel | ||
297 | * | ||
298 | * Note that children of the provided root are not instanciated as devices | ||
299 | * unless the specified root itself matches the bus list and is not NULL. | ||
300 | */ | ||
301 | |||
302 | int of_platform_bus_probe(struct device_node *root, | ||
303 | struct of_device_id *matches, | ||
304 | struct device *parent) | ||
305 | { | ||
306 | struct device_node *child; | ||
307 | struct of_device *dev; | ||
308 | int rc = 0; | ||
309 | |||
310 | if (matches == NULL) | ||
311 | matches = of_default_bus_ids; | ||
312 | if (matches == OF_NO_DEEP_PROBE) | ||
313 | return -EINVAL; | ||
314 | if (root == NULL) | ||
315 | root = of_find_node_by_path("/"); | ||
316 | else | ||
317 | of_node_get(root); | ||
318 | |||
319 | pr_debug("of_platform_bus_probe()\n"); | ||
320 | pr_debug(" starting at: %s\n", root->full_name); | ||
321 | |||
322 | /* Do a self check of bus type, if there's a match, create | ||
323 | * children | ||
324 | */ | ||
325 | if (of_match_node(matches, root)) { | ||
326 | pr_debug(" root match, create all sub devices\n"); | ||
327 | dev = of_platform_device_create(root, NULL, parent); | ||
328 | if (dev == NULL) { | ||
329 | rc = -ENOMEM; | ||
330 | goto bail; | ||
331 | } | ||
332 | pr_debug(" create all sub busses\n"); | ||
333 | rc = of_platform_bus_create(root, matches, &dev->dev); | ||
334 | goto bail; | ||
335 | } | ||
336 | for (child = NULL; (child = of_get_next_child(root, child)); ) { | ||
337 | if (!of_match_node(matches, child)) | ||
338 | continue; | ||
339 | |||
340 | pr_debug(" match: %s\n", child->full_name); | ||
341 | dev = of_platform_device_create(child, NULL, parent); | ||
342 | if (dev == NULL) | ||
343 | rc = -ENOMEM; | ||
344 | else | ||
345 | rc = of_platform_bus_create(child, matches, &dev->dev); | ||
346 | if (rc) { | ||
347 | of_node_put(child); | ||
348 | break; | ||
349 | } | ||
350 | } | ||
351 | bail: | ||
352 | of_node_put(root); | ||
353 | return rc; | ||
354 | } | ||
355 | EXPORT_SYMBOL(of_platform_bus_probe); | ||
356 | |||
357 | static int of_dev_node_match(struct device *dev, void *data) | ||
358 | { | ||
359 | return to_of_device(dev)->node == data; | ||
360 | } | ||
361 | |||
362 | struct of_device *of_find_device_by_node(struct device_node *np) | ||
363 | { | ||
364 | struct device *dev; | ||
365 | |||
366 | dev = bus_find_device(&of_platform_bus_type, | ||
367 | NULL, np, of_dev_node_match); | ||
368 | if (dev) | ||
369 | return to_of_device(dev); | ||
370 | return NULL; | ||
371 | } | ||
372 | EXPORT_SYMBOL(of_find_device_by_node); | ||
373 | |||
374 | static int of_dev_phandle_match(struct device *dev, void *data) | ||
375 | { | ||
376 | phandle *ph = data; | ||
377 | return to_of_device(dev)->node->linux_phandle == *ph; | ||
378 | } | ||
379 | |||
380 | struct of_device *of_find_device_by_phandle(phandle ph) | ||
381 | { | ||
382 | struct device *dev; | ||
383 | |||
384 | dev = bus_find_device(&of_platform_bus_type, | ||
385 | NULL, &ph, of_dev_phandle_match); | ||
386 | if (dev) | ||
387 | return to_of_device(dev); | ||
388 | return NULL; | ||
389 | } | ||
390 | EXPORT_SYMBOL(of_find_device_by_phandle); | ||
391 | |||
392 | |||
393 | #ifdef CONFIG_PPC_OF_PLATFORM_PCI | ||
394 | |||
395 | /* The probing of PCI controllers from of_platform is currently | ||
396 | * 64 bits only, mostly due to gratuitous differences between | ||
397 | * the 32 and 64 bits PCI code on PowerPC and the 32 bits one | ||
398 | * lacking some bits needed here. | ||
399 | */ | ||
400 | |||
401 | static int __devinit of_pci_phb_probe(struct of_device *dev, | ||
402 | const struct of_device_id *match) | ||
403 | { | ||
404 | struct pci_controller *phb; | ||
405 | |||
406 | /* Check if we can do that ... */ | ||
407 | if (ppc_md.pci_setup_phb == NULL) | ||
408 | return -ENODEV; | ||
409 | |||
410 | printk(KERN_INFO "Setting up PCI bus %s\n", dev->node->full_name); | ||
411 | |||
412 | /* Alloc and setup PHB data structure */ | ||
413 | phb = pcibios_alloc_controller(dev->node); | ||
414 | if (!phb) | ||
415 | return -ENODEV; | ||
416 | |||
417 | /* Setup parent in sysfs */ | ||
418 | phb->parent = &dev->dev; | ||
419 | |||
420 | /* Setup the PHB using arch provided callback */ | ||
421 | if (ppc_md.pci_setup_phb(phb)) { | ||
422 | pcibios_free_controller(phb); | ||
423 | return -ENODEV; | ||
424 | } | ||
425 | |||
426 | /* Process "ranges" property */ | ||
427 | pci_process_bridge_OF_ranges(phb, dev->node, 0); | ||
428 | |||
429 | /* Setup IO space. | ||
430 | * This will not work properly for ISA IOs, something needs to be done | ||
431 | * about it if we ever generalize that way of probing PCI brigdes | ||
432 | */ | ||
433 | pci_setup_phb_io_dynamic(phb, 0); | ||
434 | |||
435 | /* Init pci_dn data structures */ | ||
436 | pci_devs_phb_init_dynamic(phb); | ||
437 | |||
438 | /* Register devices with EEH */ | ||
439 | #ifdef CONFIG_EEH | ||
440 | if (dev->node->child) | ||
441 | eeh_add_device_tree_early(dev->node); | ||
442 | #endif /* CONFIG_EEH */ | ||
443 | |||
444 | /* Scan the bus */ | ||
445 | scan_phb(phb); | ||
446 | |||
447 | /* Claim resources. This might need some rework as well depending | ||
448 | * wether we are doing probe-only or not, like assigning unassigned | ||
449 | * resources etc... | ||
450 | */ | ||
451 | pcibios_claim_one_bus(phb->bus); | ||
452 | |||
453 | /* Finish EEH setup */ | ||
454 | #ifdef CONFIG_EEH | ||
455 | eeh_add_device_tree_late(phb->bus); | ||
456 | #endif | ||
457 | |||
458 | /* Add probed PCI devices to the device model */ | ||
459 | pci_bus_add_devices(phb->bus); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct of_device_id of_pci_phb_ids[] = { | ||
465 | { .type = "pci", }, | ||
466 | { .type = "pcix", }, | ||
467 | { .type = "pcie", }, | ||
468 | { .type = "pciex", }, | ||
469 | { .type = "ht", }, | ||
470 | {} | ||
471 | }; | ||
472 | |||
473 | static struct of_platform_driver of_pci_phb_driver = { | ||
474 | .name = "of-pci", | ||
475 | .match_table = of_pci_phb_ids, | ||
476 | .probe = of_pci_phb_probe, | ||
477 | .driver = { | ||
478 | .multithread_probe = 1, | ||
479 | }, | ||
480 | }; | ||
481 | |||
482 | static __init int of_pci_phb_init(void) | ||
483 | { | ||
484 | return of_register_platform_driver(&of_pci_phb_driver); | ||
485 | } | ||
486 | |||
487 | device_initcall(of_pci_phb_init); | ||
488 | |||
489 | #endif /* CONFIG_PPC_OF_PLATFORM_PCI */ | ||
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 9b49f8691d29..8336deafc624 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/bootmem.h> | 13 | #include <linux/bootmem.h> |
14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/list.h> | ||
15 | 16 | ||
16 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
17 | #include <asm/io.h> | 18 | #include <asm/io.h> |
@@ -99,7 +100,7 @@ pcibios_fixup_resources(struct pci_dev *dev) | |||
99 | continue; | 100 | continue; |
100 | if (res->end == 0xffffffff) { | 101 | if (res->end == 0xffffffff) { |
101 | DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n", | 102 | DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n", |
102 | pci_name(dev), i, res->start, res->end); | 103 | pci_name(dev), i, (u64)res->start, (u64)res->end); |
103 | res->end -= res->start; | 104 | res->end -= res->start; |
104 | res->start = 0; | 105 | res->start = 0; |
105 | res->flags |= IORESOURCE_UNSET; | 106 | res->flags |= IORESOURCE_UNSET; |
@@ -115,11 +116,9 @@ pcibios_fixup_resources(struct pci_dev *dev) | |||
115 | if (offset != 0) { | 116 | if (offset != 0) { |
116 | res->start += offset; | 117 | res->start += offset; |
117 | res->end += offset; | 118 | res->end += offset; |
118 | #ifdef DEBUG | 119 | DBG("Fixup res %d (%lx) of dev %s: %llx -> %llx\n", |
119 | printk("Fixup res %d (%lx) of dev %s: %llx -> %llx\n", | 120 | i, res->flags, pci_name(dev), |
120 | i, res->flags, pci_name(dev), | 121 | (u64)res->start - offset, (u64)res->start); |
121 | res->start - offset, res->start); | ||
122 | #endif | ||
123 | } | 122 | } |
124 | } | 123 | } |
125 | 124 | ||
@@ -255,7 +254,7 @@ pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
255 | } | 254 | } |
256 | 255 | ||
257 | DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n", | 256 | DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n", |
258 | res->start, res->end, res->flags, pr); | 257 | (u64)res->start, (u64)res->end, res->flags, pr); |
259 | if (pr) { | 258 | if (pr) { |
260 | if (request_resource(pr, res) == 0) | 259 | if (request_resource(pr, res) == 0) |
261 | continue; | 260 | continue; |
@@ -306,7 +305,7 @@ reparent_resources(struct resource *parent, struct resource *res) | |||
306 | for (p = res->child; p != NULL; p = p->sibling) { | 305 | for (p = res->child; p != NULL; p = p->sibling) { |
307 | p->parent = res; | 306 | p->parent = res; |
308 | DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n", | 307 | DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n", |
309 | p->name, p->start, p->end, res->name); | 308 | p->name, (u64)p->start, (u64)p->end, res->name); |
310 | } | 309 | } |
311 | return 0; | 310 | return 0; |
312 | } | 311 | } |
@@ -362,7 +361,7 @@ pci_relocate_bridge_resource(struct pci_bus *bus, int i) | |||
362 | } | 361 | } |
363 | if (request_resource(pr, res)) { | 362 | if (request_resource(pr, res)) { |
364 | DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n", | 363 | DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n", |
365 | res->start, res->end); | 364 | (u64)res->start, (u64)res->end); |
366 | return -1; /* "can't happen" */ | 365 | return -1; /* "can't happen" */ |
367 | } | 366 | } |
368 | update_bridge_base(bus, i); | 367 | update_bridge_base(bus, i); |
@@ -441,14 +440,14 @@ update_bridge_base(struct pci_bus *bus, int i) | |||
441 | end = res->end - off; | 440 | end = res->end - off; |
442 | io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK; | 441 | io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK; |
443 | io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK; | 442 | io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK; |
444 | if (end > 0xffff) { | 443 | if (end > 0xffff) |
445 | pci_write_config_word(dev, PCI_IO_BASE_UPPER16, | ||
446 | start >> 16); | ||
447 | pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, | ||
448 | end >> 16); | ||
449 | io_base_lo |= PCI_IO_RANGE_TYPE_32; | 444 | io_base_lo |= PCI_IO_RANGE_TYPE_32; |
450 | } else | 445 | else |
451 | io_base_lo |= PCI_IO_RANGE_TYPE_16; | 446 | io_base_lo |= PCI_IO_RANGE_TYPE_16; |
447 | pci_write_config_word(dev, PCI_IO_BASE_UPPER16, | ||
448 | start >> 16); | ||
449 | pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, | ||
450 | end >> 16); | ||
452 | pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo); | 451 | pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo); |
453 | pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo); | 452 | pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo); |
454 | 453 | ||
@@ -480,14 +479,14 @@ static inline void alloc_resource(struct pci_dev *dev, int idx) | |||
480 | struct resource *pr, *r = &dev->resource[idx]; | 479 | struct resource *pr, *r = &dev->resource[idx]; |
481 | 480 | ||
482 | DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n", | 481 | DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n", |
483 | pci_name(dev), idx, r->start, r->end, r->flags); | 482 | pci_name(dev), idx, (u64)r->start, (u64)r->end, r->flags); |
484 | pr = pci_find_parent_resource(dev, r); | 483 | pr = pci_find_parent_resource(dev, r); |
485 | if (!pr || request_resource(pr, r) < 0) { | 484 | if (!pr || request_resource(pr, r) < 0) { |
486 | printk(KERN_ERR "PCI: Cannot allocate resource region %d" | 485 | printk(KERN_ERR "PCI: Cannot allocate resource region %d" |
487 | " of device %s\n", idx, pci_name(dev)); | 486 | " of device %s\n", idx, pci_name(dev)); |
488 | if (pr) | 487 | if (pr) |
489 | DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n", | 488 | DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n", |
490 | pr, pr->start, pr->end, pr->flags); | 489 | pr, (u64)pr->start, (u64)pr->end, pr->flags); |
491 | /* We'll assign a new address later */ | 490 | /* We'll assign a new address later */ |
492 | r->flags |= IORESOURCE_UNSET; | 491 | r->flags |= IORESOURCE_UNSET; |
493 | r->end -= r->start; | 492 | r->end -= r->start; |
@@ -737,25 +736,51 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* | |||
737 | return NULL; | 736 | return NULL; |
738 | } | 737 | } |
739 | 738 | ||
740 | static int | 739 | static struct device_node *scan_OF_for_pci_dev(struct device_node *parent, |
741 | scan_OF_pci_childs_iterator(struct device_node* node, void* data) | 740 | unsigned int devfn) |
742 | { | 741 | { |
743 | const unsigned int *reg; | 742 | struct device_node *np = NULL; |
744 | u8* fdata = (u8*)data; | 743 | const u32 *reg; |
745 | 744 | unsigned int psize; | |
746 | reg = get_property(node, "reg", NULL); | 745 | |
747 | if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] | 746 | while ((np = of_get_next_child(parent, np)) != NULL) { |
748 | && ((reg[0] >> 16) & 0xff) == fdata[0]) | 747 | reg = get_property(np, "reg", &psize); |
749 | return 1; | 748 | if (reg == NULL || psize < 4) |
750 | return 0; | 749 | continue; |
750 | if (((reg[0] >> 8) & 0xff) == devfn) | ||
751 | return np; | ||
752 | } | ||
753 | return NULL; | ||
751 | } | 754 | } |
752 | 755 | ||
753 | static struct device_node* | 756 | |
754 | scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) | 757 | static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus) |
755 | { | 758 | { |
756 | u8 filter_data[2] = {bus, dev_fn}; | 759 | struct device_node *parent, *np; |
760 | |||
761 | /* Are we a root bus ? */ | ||
762 | if (bus->self == NULL || bus->parent == NULL) { | ||
763 | struct pci_controller *hose = pci_bus_to_hose(bus->number); | ||
764 | if (hose == NULL) | ||
765 | return NULL; | ||
766 | return of_node_get(hose->arch_data); | ||
767 | } | ||
757 | 768 | ||
758 | return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data); | 769 | /* not a root bus, we need to get our parent */ |
770 | parent = scan_OF_for_pci_bus(bus->parent); | ||
771 | if (parent == NULL) | ||
772 | return NULL; | ||
773 | |||
774 | /* now iterate for children for a match */ | ||
775 | np = scan_OF_for_pci_dev(parent, bus->self->devfn); | ||
776 | of_node_put(parent); | ||
777 | |||
778 | /* sanity check */ | ||
779 | if (strcmp(np->type, "pci") != 0) | ||
780 | printk(KERN_WARNING "pci: wrong type \"%s\" for bridge %s\n", | ||
781 | np->type, np->full_name); | ||
782 | |||
783 | return np; | ||
759 | } | 784 | } |
760 | 785 | ||
761 | /* | 786 | /* |
@@ -764,43 +789,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) | |||
764 | struct device_node * | 789 | struct device_node * |
765 | pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) | 790 | pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) |
766 | { | 791 | { |
767 | struct pci_controller *hose; | 792 | struct device_node *parent, *np; |
768 | struct device_node *node; | ||
769 | int busnr; | ||
770 | 793 | ||
771 | if (!have_of) | 794 | if (!have_of) |
772 | return NULL; | 795 | return NULL; |
773 | |||
774 | /* Lookup the hose */ | ||
775 | busnr = bus->number; | ||
776 | hose = pci_bus_to_hose(busnr); | ||
777 | if (!hose) | ||
778 | return NULL; | ||
779 | 796 | ||
780 | /* Check it has an OF node associated */ | 797 | DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn); |
781 | node = (struct device_node *) hose->arch_data; | 798 | parent = scan_OF_for_pci_bus(bus); |
782 | if (!node) | 799 | if (parent == NULL) |
783 | return NULL; | 800 | return NULL; |
784 | 801 | DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>"); | |
785 | /* Fixup bus number according to what OF think it is. */ | 802 | np = scan_OF_for_pci_dev(parent, devfn); |
786 | #ifdef CONFIG_PPC_PMAC | 803 | of_node_put(parent); |
787 | /* The G5 need a special case here. Basically, we don't remap all | 804 | DBG(" result is %s\n", np ? np->full_name : "<NULL>"); |
788 | * busses on it so we don't create the pci-OF-map. However, we do | 805 | |
789 | * remap the AGP bus and so have to deal with it. A future better | 806 | /* XXX most callers don't release the returned node |
790 | * fix has to be done by making the remapping per-host and always | 807 | * mostly because ppc64 doesn't increase the refcount, |
791 | * filling the pci_to_OF map. --BenH | 808 | * we need to fix that. |
792 | */ | 809 | */ |
793 | if (machine_is(powermac) && busnr >= 0xf0) | 810 | return np; |
794 | busnr -= 0xf0; | ||
795 | else | ||
796 | #endif | ||
797 | if (pci_to_OF_bus_map) | ||
798 | busnr = pci_to_OF_bus_map[busnr]; | ||
799 | if (busnr == 0xff) | ||
800 | return NULL; | ||
801 | |||
802 | /* Now, lookup childs of the hose */ | ||
803 | return scan_OF_childs_for_device(node->child, busnr, devfn); | ||
804 | } | 811 | } |
805 | EXPORT_SYMBOL(pci_busdev_to_OF_node); | 812 | EXPORT_SYMBOL(pci_busdev_to_OF_node); |
806 | 813 | ||
@@ -960,7 +967,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, | |||
960 | res->flags = IORESOURCE_IO; | 967 | res->flags = IORESOURCE_IO; |
961 | res->start = ranges[2]; | 968 | res->start = ranges[2]; |
962 | DBG("PCI: IO 0x%llx -> 0x%llx\n", | 969 | DBG("PCI: IO 0x%llx -> 0x%llx\n", |
963 | res->start, res->start + size - 1); | 970 | (u64)res->start, (u64)res->start + size - 1); |
964 | break; | 971 | break; |
965 | case 2: /* memory space */ | 972 | case 2: /* memory space */ |
966 | memno = 0; | 973 | memno = 0; |
@@ -982,7 +989,7 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, | |||
982 | res->flags |= IORESOURCE_PREFETCH; | 989 | res->flags |= IORESOURCE_PREFETCH; |
983 | res->start = ranges[na+2]; | 990 | res->start = ranges[na+2]; |
984 | DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno, | 991 | DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno, |
985 | res->start, res->start + size - 1); | 992 | (u64)res->start, (u64)res->start + size - 1); |
986 | } | 993 | } |
987 | break; | 994 | break; |
988 | } | 995 | } |
@@ -1268,7 +1275,10 @@ pcibios_init(void) | |||
1268 | if (pci_assign_all_buses) | 1275 | if (pci_assign_all_buses) |
1269 | hose->first_busno = next_busno; | 1276 | hose->first_busno = next_busno; |
1270 | hose->last_busno = 0xff; | 1277 | hose->last_busno = 0xff; |
1271 | bus = pci_scan_bus(hose->first_busno, hose->ops, hose); | 1278 | bus = pci_scan_bus_parented(hose->parent, hose->first_busno, |
1279 | hose->ops, hose); | ||
1280 | if (bus) | ||
1281 | pci_bus_add_devices(bus); | ||
1272 | hose->last_busno = bus->subordinate; | 1282 | hose->last_busno = bus->subordinate; |
1273 | if (pci_assign_all_buses || next_busno <= hose->last_busno) | 1283 | if (pci_assign_all_buses || next_busno <= hose->last_busno) |
1274 | next_busno = hose->last_busno + pcibios_assign_bus_offset; | 1284 | next_busno = hose->last_busno + pcibios_assign_bus_offset; |
@@ -1282,10 +1292,6 @@ pcibios_init(void) | |||
1282 | if (pci_assign_all_buses && have_of) | 1292 | if (pci_assign_all_buses && have_of) |
1283 | pcibios_make_OF_bus_map(); | 1293 | pcibios_make_OF_bus_map(); |
1284 | 1294 | ||
1285 | /* Do machine dependent PCI interrupt routing */ | ||
1286 | if (ppc_md.pci_swizzle && ppc_md.pci_map_irq) | ||
1287 | pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq); | ||
1288 | |||
1289 | /* Call machine dependent fixup */ | 1295 | /* Call machine dependent fixup */ |
1290 | if (ppc_md.pcibios_fixup) | 1296 | if (ppc_md.pcibios_fixup) |
1291 | ppc_md.pcibios_fixup(); | 1297 | ppc_md.pcibios_fixup(); |
@@ -1308,25 +1314,6 @@ pcibios_init(void) | |||
1308 | 1314 | ||
1309 | subsys_initcall(pcibios_init); | 1315 | subsys_initcall(pcibios_init); |
1310 | 1316 | ||
1311 | unsigned char __init | ||
1312 | common_swizzle(struct pci_dev *dev, unsigned char *pinp) | ||
1313 | { | ||
1314 | struct pci_controller *hose = dev->sysdata; | ||
1315 | |||
1316 | if (dev->bus->number != hose->first_busno) { | ||
1317 | u8 pin = *pinp; | ||
1318 | do { | ||
1319 | pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); | ||
1320 | /* Move up the chain of bridges. */ | ||
1321 | dev = dev->bus->self; | ||
1322 | } while (dev->bus->self); | ||
1323 | *pinp = pin; | ||
1324 | |||
1325 | /* The slot is the idsel of the last bridge. */ | ||
1326 | } | ||
1327 | return PCI_SLOT(dev->devfn); | ||
1328 | } | ||
1329 | |||
1330 | unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, | 1317 | unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, |
1331 | unsigned long start, unsigned long size) | 1318 | unsigned long start, unsigned long size) |
1332 | { | 1319 | { |
@@ -1338,6 +1325,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) | |||
1338 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | 1325 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; |
1339 | unsigned long io_offset; | 1326 | unsigned long io_offset; |
1340 | struct resource *res; | 1327 | struct resource *res; |
1328 | struct pci_dev *dev; | ||
1341 | int i; | 1329 | int i; |
1342 | 1330 | ||
1343 | io_offset = (unsigned long)hose->io_base_virt - isa_io_base; | 1331 | io_offset = (unsigned long)hose->io_base_virt - isa_io_base; |
@@ -1390,8 +1378,16 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) | |||
1390 | } | 1378 | } |
1391 | } | 1379 | } |
1392 | 1380 | ||
1381 | /* Platform specific bus fixups */ | ||
1393 | if (ppc_md.pcibios_fixup_bus) | 1382 | if (ppc_md.pcibios_fixup_bus) |
1394 | ppc_md.pcibios_fixup_bus(bus); | 1383 | ppc_md.pcibios_fixup_bus(bus); |
1384 | |||
1385 | /* Read default IRQs and fixup if necessary */ | ||
1386 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
1387 | pci_read_irq_line(dev); | ||
1388 | if (ppc_md.pci_irq_fixup) | ||
1389 | ppc_md.pci_irq_fixup(dev); | ||
1390 | } | ||
1395 | } | 1391 | } |
1396 | 1392 | ||
1397 | char __init *pcibios_setup(char *str) | 1393 | char __init *pcibios_setup(char *str) |
@@ -1556,7 +1552,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) | |||
1556 | 1552 | ||
1557 | 1553 | ||
1558 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | 1554 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, |
1559 | unsigned long *offset, | 1555 | resource_size_t *offset, |
1560 | enum pci_mmap_state mmap_state) | 1556 | enum pci_mmap_state mmap_state) |
1561 | { | 1557 | { |
1562 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | 1558 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); |
@@ -1568,10 +1564,12 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
1568 | 1564 | ||
1569 | /* If memory, add on the PCI bridge address offset */ | 1565 | /* If memory, add on the PCI bridge address offset */ |
1570 | if (mmap_state == pci_mmap_mem) { | 1566 | if (mmap_state == pci_mmap_mem) { |
1567 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
1571 | *offset += hose->pci_mem_offset; | 1568 | *offset += hose->pci_mem_offset; |
1569 | #endif | ||
1572 | res_bit = IORESOURCE_MEM; | 1570 | res_bit = IORESOURCE_MEM; |
1573 | } else { | 1571 | } else { |
1574 | io_offset = hose->io_base_virt - ___IO_BASE; | 1572 | io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE; |
1575 | *offset += io_offset; | 1573 | *offset += io_offset; |
1576 | res_bit = IORESOURCE_IO; | 1574 | res_bit = IORESOURCE_IO; |
1577 | } | 1575 | } |
@@ -1636,9 +1634,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, | |||
1636 | else | 1634 | else |
1637 | prot |= _PAGE_GUARDED; | 1635 | prot |= _PAGE_GUARDED; |
1638 | 1636 | ||
1639 | printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev), | ||
1640 | (unsigned long long)rp->start, prot); | ||
1641 | |||
1642 | return __pgprot(prot); | 1637 | return __pgprot(prot); |
1643 | } | 1638 | } |
1644 | 1639 | ||
@@ -1707,7 +1702,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | |||
1707 | enum pci_mmap_state mmap_state, | 1702 | enum pci_mmap_state mmap_state, |
1708 | int write_combine) | 1703 | int write_combine) |
1709 | { | 1704 | { |
1710 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 1705 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; |
1711 | struct resource *rp; | 1706 | struct resource *rp; |
1712 | int ret; | 1707 | int ret; |
1713 | 1708 | ||
@@ -1820,21 +1815,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, | |||
1820 | resource_size_t *start, resource_size_t *end) | 1815 | resource_size_t *start, resource_size_t *end) |
1821 | { | 1816 | { |
1822 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | 1817 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); |
1823 | unsigned long offset = 0; | 1818 | resource_size_t offset = 0; |
1824 | 1819 | ||
1825 | if (hose == NULL) | 1820 | if (hose == NULL) |
1826 | return; | 1821 | return; |
1827 | 1822 | ||
1828 | if (rsrc->flags & IORESOURCE_IO) | 1823 | if (rsrc->flags & IORESOURCE_IO) |
1829 | offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; | 1824 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; |
1825 | |||
1826 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
1827 | * a BAR value because X is lame and expects to be able to use that | ||
1828 | * to pass to /dev/mem ! | ||
1829 | * | ||
1830 | * That means that we'll have potentially 64 bits values where some | ||
1831 | * userland apps only expect 32 (like X itself since it thinks only | ||
1832 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
1833 | * 32 bits CHRPs :-( | ||
1834 | * | ||
1835 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
1836 | * has been fixed (and the fix spread enough), we can re-enable the | ||
1837 | * 2 lines below and pass down a BAR value to userland. In that case | ||
1838 | * we'll also have to re-enable the matching code in | ||
1839 | * __pci_mmap_make_offset(). | ||
1840 | * | ||
1841 | * BenH. | ||
1842 | */ | ||
1843 | #if 0 | ||
1844 | else if (rsrc->flags & IORESOURCE_MEM) | ||
1845 | offset = hose->pci_mem_offset; | ||
1846 | #endif | ||
1830 | 1847 | ||
1831 | *start = rsrc->start + offset; | 1848 | *start = rsrc->start - offset; |
1832 | *end = rsrc->end + offset; | 1849 | *end = rsrc->end - offset; |
1833 | } | 1850 | } |
1834 | 1851 | ||
1835 | void __init | 1852 | void __init pci_init_resource(struct resource *res, resource_size_t start, |
1836 | pci_init_resource(struct resource *res, unsigned long start, unsigned long end, | 1853 | resource_size_t end, int flags, char *name) |
1837 | int flags, char *name) | ||
1838 | { | 1854 | { |
1839 | res->start = start; | 1855 | res->start = start; |
1840 | res->end = end; | 1856 | res->end = end; |
@@ -1845,35 +1861,6 @@ pci_init_resource(struct resource *res, unsigned long start, unsigned long end, | |||
1845 | res->child = NULL; | 1861 | res->child = NULL; |
1846 | } | 1862 | } |
1847 | 1863 | ||
1848 | void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) | ||
1849 | { | ||
1850 | unsigned long start = pci_resource_start(dev, bar); | ||
1851 | unsigned long len = pci_resource_len(dev, bar); | ||
1852 | unsigned long flags = pci_resource_flags(dev, bar); | ||
1853 | |||
1854 | if (!len) | ||
1855 | return NULL; | ||
1856 | if (max && len > max) | ||
1857 | len = max; | ||
1858 | if (flags & IORESOURCE_IO) | ||
1859 | return ioport_map(start, len); | ||
1860 | if (flags & IORESOURCE_MEM) | ||
1861 | /* Not checking IORESOURCE_CACHEABLE because PPC does | ||
1862 | * not currently distinguish between ioremap and | ||
1863 | * ioremap_nocache. | ||
1864 | */ | ||
1865 | return ioremap(start, len); | ||
1866 | /* What? */ | ||
1867 | return NULL; | ||
1868 | } | ||
1869 | |||
1870 | void pci_iounmap(struct pci_dev *dev, void __iomem *addr) | ||
1871 | { | ||
1872 | /* Nothing to do */ | ||
1873 | } | ||
1874 | EXPORT_SYMBOL(pci_iomap); | ||
1875 | EXPORT_SYMBOL(pci_iounmap); | ||
1876 | |||
1877 | unsigned long pci_address_to_pio(phys_addr_t address) | 1864 | unsigned long pci_address_to_pio(phys_addr_t address) |
1878 | { | 1865 | { |
1879 | struct pci_controller* hose = hose_head; | 1866 | struct pci_controller* hose = hose_head; |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 78d3c0fc8dfb..a6b7692c7269 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -42,11 +42,9 @@ | |||
42 | unsigned long pci_probe_only = 1; | 42 | unsigned long pci_probe_only = 1; |
43 | int pci_assign_all_buses = 0; | 43 | int pci_assign_all_buses = 0; |
44 | 44 | ||
45 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
46 | static void fixup_resource(struct resource *res, struct pci_dev *dev); | 45 | static void fixup_resource(struct resource *res, struct pci_dev *dev); |
47 | static void do_bus_setup(struct pci_bus *bus); | 46 | static void do_bus_setup(struct pci_bus *bus); |
48 | static void phbs_remap_io(void); | 47 | static void phbs_remap_io(void); |
49 | #endif | ||
50 | 48 | ||
51 | /* pci_io_base -- the base address from which io bars are offsets. | 49 | /* pci_io_base -- the base address from which io bars are offsets. |
52 | * This is the lowest I/O base address (so bar values are always positive), | 50 | * This is the lowest I/O base address (so bar values are always positive), |
@@ -63,7 +61,7 @@ void iSeries_pcibios_init(void); | |||
63 | 61 | ||
64 | LIST_HEAD(hose_list); | 62 | LIST_HEAD(hose_list); |
65 | 63 | ||
66 | struct dma_mapping_ops pci_dma_ops; | 64 | struct dma_mapping_ops *pci_dma_ops; |
67 | EXPORT_SYMBOL(pci_dma_ops); | 65 | EXPORT_SYMBOL(pci_dma_ops); |
68 | 66 | ||
69 | int global_phb_number; /* Global phb counter */ | 67 | int global_phb_number; /* Global phb counter */ |
@@ -199,13 +197,23 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev) | |||
199 | pci_setup_pci_controller(phb); | 197 | pci_setup_pci_controller(phb); |
200 | phb->arch_data = dev; | 198 | phb->arch_data = dev; |
201 | phb->is_dynamic = mem_init_done; | 199 | phb->is_dynamic = mem_init_done; |
202 | if (dev) | 200 | if (dev) { |
203 | PHB_SET_NODE(phb, of_node_to_nid(dev)); | 201 | int nid = of_node_to_nid(dev); |
202 | |||
203 | if (nid < 0 || !node_online(nid)) | ||
204 | nid = -1; | ||
205 | |||
206 | PHB_SET_NODE(phb, nid); | ||
207 | } | ||
204 | return phb; | 208 | return phb; |
205 | } | 209 | } |
206 | 210 | ||
207 | void pcibios_free_controller(struct pci_controller *phb) | 211 | void pcibios_free_controller(struct pci_controller *phb) |
208 | { | 212 | { |
213 | spin_lock(&hose_spinlock); | ||
214 | list_del(&phb->list_node); | ||
215 | spin_unlock(&hose_spinlock); | ||
216 | |||
209 | if (phb->is_dynamic) | 217 | if (phb->is_dynamic) |
210 | kfree(phb); | 218 | kfree(phb); |
211 | } | 219 | } |
@@ -245,7 +253,6 @@ static void __init pcibios_claim_of_setup(void) | |||
245 | pcibios_claim_one_bus(b); | 253 | pcibios_claim_one_bus(b); |
246 | } | 254 | } |
247 | 255 | ||
248 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
249 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) | 256 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) |
250 | { | 257 | { |
251 | const u32 *prop; | 258 | const u32 *prop; |
@@ -323,7 +330,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
323 | struct pci_dev *dev; | 330 | struct pci_dev *dev; |
324 | const char *type; | 331 | const char *type; |
325 | 332 | ||
326 | dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); | 333 | dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL); |
327 | if (!dev) | 334 | if (!dev) |
328 | return NULL; | 335 | return NULL; |
329 | type = get_property(node, "device_type", NULL); | 336 | type = get_property(node, "device_type", NULL); |
@@ -332,7 +339,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
332 | 339 | ||
333 | DBG(" create device, devfn: %x, type: %s\n", devfn, type); | 340 | DBG(" create device, devfn: %x, type: %s\n", devfn, type); |
334 | 341 | ||
335 | memset(dev, 0, sizeof(struct pci_dev)); | ||
336 | dev->bus = bus; | 342 | dev->bus = bus; |
337 | dev->sysdata = node; | 343 | dev->sysdata = node; |
338 | dev->dev.parent = bus->bridge; | 344 | dev->dev.parent = bus->bridge; |
@@ -500,7 +506,6 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
500 | pci_scan_child_bus(bus); | 506 | pci_scan_child_bus(bus); |
501 | } | 507 | } |
502 | EXPORT_SYMBOL(of_scan_pci_bridge); | 508 | EXPORT_SYMBOL(of_scan_pci_bridge); |
503 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
504 | 509 | ||
505 | void __devinit scan_phb(struct pci_controller *hose) | 510 | void __devinit scan_phb(struct pci_controller *hose) |
506 | { | 511 | { |
@@ -511,7 +516,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
511 | 516 | ||
512 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); | 517 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); |
513 | 518 | ||
514 | bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); | 519 | bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); |
515 | if (bus == NULL) { | 520 | if (bus == NULL) { |
516 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", | 521 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", |
517 | hose->global_number); | 522 | hose->global_number); |
@@ -534,7 +539,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
534 | } | 539 | } |
535 | 540 | ||
536 | mode = PCI_PROBE_NORMAL; | 541 | mode = PCI_PROBE_NORMAL; |
537 | #ifdef CONFIG_PPC_MULTIPLATFORM | 542 | |
538 | if (node && ppc_md.pci_probe_mode) | 543 | if (node && ppc_md.pci_probe_mode) |
539 | mode = ppc_md.pci_probe_mode(bus); | 544 | mode = ppc_md.pci_probe_mode(bus); |
540 | DBG(" probe mode: %d\n", mode); | 545 | DBG(" probe mode: %d\n", mode); |
@@ -542,7 +547,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
542 | bus->subordinate = hose->last_busno; | 547 | bus->subordinate = hose->last_busno; |
543 | of_scan_bus(node, bus); | 548 | of_scan_bus(node, bus); |
544 | } | 549 | } |
545 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 550 | |
546 | if (mode == PCI_PROBE_NORMAL) | 551 | if (mode == PCI_PROBE_NORMAL) |
547 | hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); | 552 | hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); |
548 | } | 553 | } |
@@ -586,11 +591,9 @@ static int __init pcibios_init(void) | |||
586 | if (ppc64_isabridge_dev != NULL) | 591 | if (ppc64_isabridge_dev != NULL) |
587 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); | 592 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); |
588 | 593 | ||
589 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
590 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 594 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) |
591 | /* map in PCI I/O space */ | 595 | /* map in PCI I/O space */ |
592 | phbs_remap_io(); | 596 | phbs_remap_io(); |
593 | #endif | ||
594 | 597 | ||
595 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); | 598 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); |
596 | 599 | ||
@@ -679,7 +682,7 @@ int pci_proc_domain(struct pci_bus *bus) | |||
679 | * Returns negative error code on failure, zero on success. | 682 | * Returns negative error code on failure, zero on success. |
680 | */ | 683 | */ |
681 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | 684 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, |
682 | unsigned long *offset, | 685 | resource_size_t *offset, |
683 | enum pci_mmap_state mmap_state) | 686 | enum pci_mmap_state mmap_state) |
684 | { | 687 | { |
685 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | 688 | struct pci_controller *hose = pci_bus_to_host(dev->bus); |
@@ -691,7 +694,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
691 | 694 | ||
692 | /* If memory, add on the PCI bridge address offset */ | 695 | /* If memory, add on the PCI bridge address offset */ |
693 | if (mmap_state == pci_mmap_mem) { | 696 | if (mmap_state == pci_mmap_mem) { |
697 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
694 | *offset += hose->pci_mem_offset; | 698 | *offset += hose->pci_mem_offset; |
699 | #endif | ||
695 | res_bit = IORESOURCE_MEM; | 700 | res_bit = IORESOURCE_MEM; |
696 | } else { | 701 | } else { |
697 | io_offset = (unsigned long)hose->io_base_virt - pci_io_base; | 702 | io_offset = (unsigned long)hose->io_base_virt - pci_io_base; |
@@ -759,9 +764,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, | |||
759 | else | 764 | else |
760 | prot |= _PAGE_GUARDED; | 765 | prot |= _PAGE_GUARDED; |
761 | 766 | ||
762 | printk(KERN_DEBUG "PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start, | ||
763 | prot); | ||
764 | |||
765 | return __pgprot(prot); | 767 | return __pgprot(prot); |
766 | } | 768 | } |
767 | 769 | ||
@@ -829,7 +831,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, | |||
829 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | 831 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, |
830 | enum pci_mmap_state mmap_state, int write_combine) | 832 | enum pci_mmap_state mmap_state, int write_combine) |
831 | { | 833 | { |
832 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 834 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; |
833 | struct resource *rp; | 835 | struct resource *rp; |
834 | int ret; | 836 | int ret; |
835 | 837 | ||
@@ -867,8 +869,6 @@ void pcibios_add_platform_entries(struct pci_dev *pdev) | |||
867 | device_create_file(&pdev->dev, &dev_attr_devspec); | 869 | device_create_file(&pdev->dev, &dev_attr_devspec); |
868 | } | 870 | } |
869 | 871 | ||
870 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
871 | |||
872 | #define ISA_SPACE_MASK 0x1 | 872 | #define ISA_SPACE_MASK 0x1 |
873 | #define ISA_SPACE_IO 0x1 | 873 | #define ISA_SPACE_IO 0x1 |
874 | 874 | ||
@@ -969,11 +969,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, | |||
969 | res = NULL; | 969 | res = NULL; |
970 | pci_space = ranges[0]; | 970 | pci_space = ranges[0]; |
971 | pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2]; | 971 | pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2]; |
972 | 972 | cpu_phys_addr = of_translate_address(dev, &ranges[3]); | |
973 | cpu_phys_addr = ranges[3]; | ||
974 | if (na >= 2) | ||
975 | cpu_phys_addr = (cpu_phys_addr << 32) | ranges[4]; | ||
976 | |||
977 | size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4]; | 973 | size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4]; |
978 | ranges += np; | 974 | ranges += np; |
979 | if (size == 0) | 975 | if (size == 0) |
@@ -1139,7 +1135,7 @@ int unmap_bus_range(struct pci_bus *bus) | |||
1139 | 1135 | ||
1140 | if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) | 1136 | if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) |
1141 | return 1; | 1137 | return 1; |
1142 | if (iounmap_explicit((void __iomem *) start_virt, size)) | 1138 | if (__iounmap_explicit((void __iomem *) start_virt, size)) |
1143 | return 1; | 1139 | return 1; |
1144 | 1140 | ||
1145 | return 0; | 1141 | return 0; |
@@ -1207,23 +1203,52 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, | |||
1207 | } | 1203 | } |
1208 | EXPORT_SYMBOL(pcibios_fixup_device_resources); | 1204 | EXPORT_SYMBOL(pcibios_fixup_device_resources); |
1209 | 1205 | ||
1206 | void __devinit pcibios_setup_new_device(struct pci_dev *dev) | ||
1207 | { | ||
1208 | struct dev_archdata *sd = &dev->dev.archdata; | ||
1209 | |||
1210 | sd->of_node = pci_device_to_OF_node(dev); | ||
1211 | |||
1212 | DBG("PCI device %s OF node: %s\n", pci_name(dev), | ||
1213 | sd->of_node ? sd->of_node->full_name : "<none>"); | ||
1214 | |||
1215 | sd->dma_ops = pci_dma_ops; | ||
1216 | #ifdef CONFIG_NUMA | ||
1217 | sd->numa_node = pcibus_to_node(dev->bus); | ||
1218 | #else | ||
1219 | sd->numa_node = -1; | ||
1220 | #endif | ||
1221 | if (ppc_md.pci_dma_dev_setup) | ||
1222 | ppc_md.pci_dma_dev_setup(dev); | ||
1223 | } | ||
1224 | EXPORT_SYMBOL(pcibios_setup_new_device); | ||
1210 | 1225 | ||
1211 | static void __devinit do_bus_setup(struct pci_bus *bus) | 1226 | static void __devinit do_bus_setup(struct pci_bus *bus) |
1212 | { | 1227 | { |
1213 | struct pci_dev *dev; | 1228 | struct pci_dev *dev; |
1214 | 1229 | ||
1215 | ppc_md.iommu_bus_setup(bus); | 1230 | if (ppc_md.pci_dma_bus_setup) |
1231 | ppc_md.pci_dma_bus_setup(bus); | ||
1216 | 1232 | ||
1217 | list_for_each_entry(dev, &bus->devices, bus_list) | 1233 | list_for_each_entry(dev, &bus->devices, bus_list) |
1218 | ppc_md.iommu_dev_setup(dev); | 1234 | pcibios_setup_new_device(dev); |
1219 | 1235 | ||
1220 | if (ppc_md.irq_bus_setup) | 1236 | /* Read default IRQs and fixup if necessary */ |
1221 | ppc_md.irq_bus_setup(bus); | 1237 | list_for_each_entry(dev, &bus->devices, bus_list) { |
1238 | pci_read_irq_line(dev); | ||
1239 | if (ppc_md.pci_irq_fixup) | ||
1240 | ppc_md.pci_irq_fixup(dev); | ||
1241 | } | ||
1222 | } | 1242 | } |
1223 | 1243 | ||
1224 | void __devinit pcibios_fixup_bus(struct pci_bus *bus) | 1244 | void __devinit pcibios_fixup_bus(struct pci_bus *bus) |
1225 | { | 1245 | { |
1226 | struct pci_dev *dev = bus->self; | 1246 | struct pci_dev *dev = bus->self; |
1247 | struct device_node *np; | ||
1248 | |||
1249 | np = pci_bus_to_OF_node(bus); | ||
1250 | |||
1251 | DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>"); | ||
1227 | 1252 | ||
1228 | if (dev && pci_probe_only && | 1253 | if (dev && pci_probe_only && |
1229 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { | 1254 | (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { |
@@ -1307,20 +1332,41 @@ EXPORT_SYMBOL(pci_read_irq_line); | |||
1307 | 1332 | ||
1308 | void pci_resource_to_user(const struct pci_dev *dev, int bar, | 1333 | void pci_resource_to_user(const struct pci_dev *dev, int bar, |
1309 | const struct resource *rsrc, | 1334 | const struct resource *rsrc, |
1310 | u64 *start, u64 *end) | 1335 | resource_size_t *start, resource_size_t *end) |
1311 | { | 1336 | { |
1312 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | 1337 | struct pci_controller *hose = pci_bus_to_host(dev->bus); |
1313 | unsigned long offset = 0; | 1338 | resource_size_t offset = 0; |
1314 | 1339 | ||
1315 | if (hose == NULL) | 1340 | if (hose == NULL) |
1316 | return; | 1341 | return; |
1317 | 1342 | ||
1318 | if (rsrc->flags & IORESOURCE_IO) | 1343 | if (rsrc->flags & IORESOURCE_IO) |
1319 | offset = pci_io_base - (unsigned long)hose->io_base_virt + | 1344 | offset = (unsigned long)hose->io_base_virt - pci_io_base; |
1320 | hose->io_base_phys; | 1345 | |
1346 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
1347 | * a BAR value because X is lame and expects to be able to use that | ||
1348 | * to pass to /dev/mem ! | ||
1349 | * | ||
1350 | * That means that we'll have potentially 64 bits values where some | ||
1351 | * userland apps only expect 32 (like X itself since it thinks only | ||
1352 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
1353 | * 32 bits CHRPs :-( | ||
1354 | * | ||
1355 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
1356 | * has been fixed (and the fix spread enough), we can re-enable the | ||
1357 | * 2 lines below and pass down a BAR value to userland. In that case | ||
1358 | * we'll also have to re-enable the matching code in | ||
1359 | * __pci_mmap_make_offset(). | ||
1360 | * | ||
1361 | * BenH. | ||
1362 | */ | ||
1363 | #if 0 | ||
1364 | else if (rsrc->flags & IORESOURCE_MEM) | ||
1365 | offset = hose->pci_mem_offset; | ||
1366 | #endif | ||
1321 | 1367 | ||
1322 | *start = rsrc->start + offset; | 1368 | *start = rsrc->start - offset; |
1323 | *end = rsrc->end + offset; | 1369 | *end = rsrc->end - offset; |
1324 | } | 1370 | } |
1325 | 1371 | ||
1326 | struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | 1372 | struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) |
@@ -1337,8 +1383,6 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | |||
1337 | return NULL; | 1383 | return NULL; |
1338 | } | 1384 | } |
1339 | 1385 | ||
1340 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
1341 | |||
1342 | unsigned long pci_address_to_pio(phys_addr_t address) | 1386 | unsigned long pci_address_to_pio(phys_addr_t address) |
1343 | { | 1387 | { |
1344 | struct pci_controller *hose, *tmp; | 1388 | struct pci_controller *hose, *tmp; |
diff --git a/arch/powerpc/kernel/pci_direct_iommu.c b/arch/powerpc/kernel/pci_direct_iommu.c deleted file mode 100644 index 72ce082ce738..000000000000 --- a/arch/powerpc/kernel/pci_direct_iommu.c +++ /dev/null | |||
@@ -1,98 +0,0 @@ | |||
1 | /* | ||
2 | * Support for DMA from PCI devices to main memory on | ||
3 | * machines without an iommu or with directly addressable | ||
4 | * RAM (typically a pmac with 2Gb of RAM or less) | ||
5 | * | ||
6 | * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | |||
23 | #include <asm/sections.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/prom.h> | ||
26 | #include <asm/pci-bridge.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/pmac_feature.h> | ||
29 | #include <asm/abs_addr.h> | ||
30 | #include <asm/ppc-pci.h> | ||
31 | |||
32 | static void *pci_direct_alloc_coherent(struct device *hwdev, size_t size, | ||
33 | dma_addr_t *dma_handle, gfp_t flag) | ||
34 | { | ||
35 | void *ret; | ||
36 | |||
37 | ret = (void *)__get_free_pages(flag, get_order(size)); | ||
38 | if (ret != NULL) { | ||
39 | memset(ret, 0, size); | ||
40 | *dma_handle = virt_to_abs(ret); | ||
41 | } | ||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | static void pci_direct_free_coherent(struct device *hwdev, size_t size, | ||
46 | void *vaddr, dma_addr_t dma_handle) | ||
47 | { | ||
48 | free_pages((unsigned long)vaddr, get_order(size)); | ||
49 | } | ||
50 | |||
51 | static dma_addr_t pci_direct_map_single(struct device *hwdev, void *ptr, | ||
52 | size_t size, enum dma_data_direction direction) | ||
53 | { | ||
54 | return virt_to_abs(ptr); | ||
55 | } | ||
56 | |||
57 | static void pci_direct_unmap_single(struct device *hwdev, dma_addr_t dma_addr, | ||
58 | size_t size, enum dma_data_direction direction) | ||
59 | { | ||
60 | } | ||
61 | |||
62 | static int pci_direct_map_sg(struct device *hwdev, struct scatterlist *sg, | ||
63 | int nents, enum dma_data_direction direction) | ||
64 | { | ||
65 | int i; | ||
66 | |||
67 | for (i = 0; i < nents; i++, sg++) { | ||
68 | sg->dma_address = page_to_phys(sg->page) + sg->offset; | ||
69 | sg->dma_length = sg->length; | ||
70 | } | ||
71 | |||
72 | return nents; | ||
73 | } | ||
74 | |||
75 | static void pci_direct_unmap_sg(struct device *hwdev, struct scatterlist *sg, | ||
76 | int nents, enum dma_data_direction direction) | ||
77 | { | ||
78 | } | ||
79 | |||
80 | static int pci_direct_dma_supported(struct device *dev, u64 mask) | ||
81 | { | ||
82 | return mask < 0x100000000ull; | ||
83 | } | ||
84 | |||
85 | static struct dma_mapping_ops pci_direct_ops = { | ||
86 | .alloc_coherent = pci_direct_alloc_coherent, | ||
87 | .free_coherent = pci_direct_free_coherent, | ||
88 | .map_single = pci_direct_map_single, | ||
89 | .unmap_single = pci_direct_unmap_single, | ||
90 | .map_sg = pci_direct_map_sg, | ||
91 | .unmap_sg = pci_direct_unmap_sg, | ||
92 | .dma_supported = pci_direct_dma_supported, | ||
93 | }; | ||
94 | |||
95 | void __init pci_direct_iommu_init(void) | ||
96 | { | ||
97 | pci_dma_ops = pci_direct_ops; | ||
98 | } | ||
diff --git a/arch/powerpc/kernel/pci_iommu.c b/arch/powerpc/kernel/pci_iommu.c deleted file mode 100644 index 0688b2534acb..000000000000 --- a/arch/powerpc/kernel/pci_iommu.c +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation | ||
3 | * | ||
4 | * Rewrite, cleanup, new allocation schemes: | ||
5 | * Copyright (C) 2004 Olof Johansson, IBM Corporation | ||
6 | * | ||
7 | * Dynamic DMA mapping support, platform-independent parts. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/dma-mapping.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/prom.h> | ||
35 | #include <asm/iommu.h> | ||
36 | #include <asm/pci-bridge.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/ppc-pci.h> | ||
39 | |||
40 | /* | ||
41 | * We can use ->sysdata directly and avoid the extra work in | ||
42 | * pci_device_to_OF_node since ->sysdata will have been initialised | ||
43 | * in the iommu init code for all devices. | ||
44 | */ | ||
45 | #define PCI_GET_DN(dev) ((struct device_node *)((dev)->sysdata)) | ||
46 | |||
47 | static inline struct iommu_table *device_to_table(struct device *hwdev) | ||
48 | { | ||
49 | struct pci_dev *pdev; | ||
50 | |||
51 | if (!hwdev) { | ||
52 | pdev = ppc64_isabridge_dev; | ||
53 | if (!pdev) | ||
54 | return NULL; | ||
55 | } else | ||
56 | pdev = to_pci_dev(hwdev); | ||
57 | |||
58 | return PCI_DN(PCI_GET_DN(pdev))->iommu_table; | ||
59 | } | ||
60 | |||
61 | |||
62 | static inline unsigned long device_to_mask(struct device *hwdev) | ||
63 | { | ||
64 | struct pci_dev *pdev; | ||
65 | |||
66 | if (!hwdev) { | ||
67 | pdev = ppc64_isabridge_dev; | ||
68 | if (!pdev) /* This is the best guess we can do */ | ||
69 | return 0xfffffffful; | ||
70 | } else | ||
71 | pdev = to_pci_dev(hwdev); | ||
72 | |||
73 | if (pdev->dma_mask) | ||
74 | return pdev->dma_mask; | ||
75 | |||
76 | /* Assume devices without mask can take 32 bit addresses */ | ||
77 | return 0xfffffffful; | ||
78 | } | ||
79 | |||
80 | |||
81 | /* Allocates a contiguous real buffer and creates mappings over it. | ||
82 | * Returns the virtual address of the buffer and sets dma_handle | ||
83 | * to the dma address (mapping) of the first page. | ||
84 | */ | ||
85 | static void *pci_iommu_alloc_coherent(struct device *hwdev, size_t size, | ||
86 | dma_addr_t *dma_handle, gfp_t flag) | ||
87 | { | ||
88 | return iommu_alloc_coherent(device_to_table(hwdev), size, dma_handle, | ||
89 | device_to_mask(hwdev), flag, | ||
90 | pcibus_to_node(to_pci_dev(hwdev)->bus)); | ||
91 | } | ||
92 | |||
93 | static void pci_iommu_free_coherent(struct device *hwdev, size_t size, | ||
94 | void *vaddr, dma_addr_t dma_handle) | ||
95 | { | ||
96 | iommu_free_coherent(device_to_table(hwdev), size, vaddr, dma_handle); | ||
97 | } | ||
98 | |||
99 | /* Creates TCEs for a user provided buffer. The user buffer must be | ||
100 | * contiguous real kernel storage (not vmalloc). The address of the buffer | ||
101 | * passed here is the kernel (virtual) address of the buffer. The buffer | ||
102 | * need not be page aligned, the dma_addr_t returned will point to the same | ||
103 | * byte within the page as vaddr. | ||
104 | */ | ||
105 | static dma_addr_t pci_iommu_map_single(struct device *hwdev, void *vaddr, | ||
106 | size_t size, enum dma_data_direction direction) | ||
107 | { | ||
108 | return iommu_map_single(device_to_table(hwdev), vaddr, size, | ||
109 | device_to_mask(hwdev), direction); | ||
110 | } | ||
111 | |||
112 | |||
113 | static void pci_iommu_unmap_single(struct device *hwdev, dma_addr_t dma_handle, | ||
114 | size_t size, enum dma_data_direction direction) | ||
115 | { | ||
116 | iommu_unmap_single(device_to_table(hwdev), dma_handle, size, direction); | ||
117 | } | ||
118 | |||
119 | |||
120 | static int pci_iommu_map_sg(struct device *pdev, struct scatterlist *sglist, | ||
121 | int nelems, enum dma_data_direction direction) | ||
122 | { | ||
123 | return iommu_map_sg(pdev, device_to_table(pdev), sglist, | ||
124 | nelems, device_to_mask(pdev), direction); | ||
125 | } | ||
126 | |||
127 | static void pci_iommu_unmap_sg(struct device *pdev, struct scatterlist *sglist, | ||
128 | int nelems, enum dma_data_direction direction) | ||
129 | { | ||
130 | iommu_unmap_sg(device_to_table(pdev), sglist, nelems, direction); | ||
131 | } | ||
132 | |||
133 | /* We support DMA to/from any memory page via the iommu */ | ||
134 | static int pci_iommu_dma_supported(struct device *dev, u64 mask) | ||
135 | { | ||
136 | struct iommu_table *tbl = device_to_table(dev); | ||
137 | |||
138 | if (!tbl || tbl->it_offset > mask) { | ||
139 | printk(KERN_INFO "Warning: IOMMU table offset too big for device mask\n"); | ||
140 | if (tbl) | ||
141 | printk(KERN_INFO "mask: 0x%08lx, table offset: 0x%08lx\n", | ||
142 | mask, tbl->it_offset); | ||
143 | else | ||
144 | printk(KERN_INFO "mask: 0x%08lx, table unavailable\n", | ||
145 | mask); | ||
146 | return 0; | ||
147 | } else | ||
148 | return 1; | ||
149 | } | ||
150 | |||
151 | struct dma_mapping_ops pci_iommu_ops = { | ||
152 | .alloc_coherent = pci_iommu_alloc_coherent, | ||
153 | .free_coherent = pci_iommu_free_coherent, | ||
154 | .map_single = pci_iommu_map_single, | ||
155 | .unmap_single = pci_iommu_unmap_single, | ||
156 | .map_sg = pci_iommu_map_sg, | ||
157 | .unmap_sg = pci_iommu_unmap_sg, | ||
158 | .dma_supported = pci_iommu_dma_supported, | ||
159 | }; | ||
160 | |||
161 | void pci_iommu_init(void) | ||
162 | { | ||
163 | pci_dma_ops = pci_iommu_ops; | ||
164 | } | ||
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/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 807193a3c784..95776b6af4e2 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -49,6 +49,10 @@ | |||
49 | #include <asm/commproc.h> | 49 | #include <asm/commproc.h> |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #ifdef CONFIG_PPC64 | ||
53 | EXPORT_SYMBOL(local_irq_restore); | ||
54 | #endif | ||
55 | |||
52 | #ifdef CONFIG_PPC32 | 56 | #ifdef CONFIG_PPC32 |
53 | extern void transfer_to_handler(void); | 57 | extern void transfer_to_handler(void); |
54 | extern void do_IRQ(struct pt_regs *regs); | 58 | extern void do_IRQ(struct pt_regs *regs); |
@@ -204,7 +208,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ | |||
204 | extern long *intercept_table; | 208 | extern long *intercept_table; |
205 | EXPORT_SYMBOL(intercept_table); | 209 | EXPORT_SYMBOL(intercept_table); |
206 | #endif /* CONFIG_PPC_STD_MMU_32 */ | 210 | #endif /* CONFIG_PPC_STD_MMU_32 */ |
207 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 211 | #ifdef CONFIG_PPC_DCR_NATIVE |
208 | EXPORT_SYMBOL(__mtdcr); | 212 | EXPORT_SYMBOL(__mtdcr); |
209 | EXPORT_SYMBOL(__mfdcr); | 213 | EXPORT_SYMBOL(__mfdcr); |
210 | #endif | 214 | #endif |
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c index f598cb519539..dd7001cacf75 100644 --- a/arch/powerpc/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_ppc64.c | |||
@@ -83,7 +83,7 @@ __initcall(proc_ppc64_init); | |||
83 | static loff_t page_map_seek( struct file *file, loff_t off, int whence) | 83 | static loff_t page_map_seek( struct file *file, loff_t off, int whence) |
84 | { | 84 | { |
85 | loff_t new; | 85 | loff_t new; |
86 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 86 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
87 | 87 | ||
88 | switch(whence) { | 88 | switch(whence) { |
89 | case 0: | 89 | case 0: |
@@ -106,13 +106,13 @@ static loff_t page_map_seek( struct file *file, loff_t off, int whence) | |||
106 | static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, | 106 | static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, |
107 | loff_t *ppos) | 107 | loff_t *ppos) |
108 | { | 108 | { |
109 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 109 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
110 | return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size); | 110 | return simple_read_from_buffer(buf, nbytes, ppos, dp->data, dp->size); |
111 | } | 111 | } |
112 | 112 | ||
113 | static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) | 113 | static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) |
114 | { | 114 | { |
115 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 115 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
116 | 116 | ||
117 | if ((vma->vm_end - vma->vm_start) > dp->size) | 117 | if ((vma->vm_end - vma->vm_start) > dp->size) |
118 | return -EINVAL; | 118 | return -EINVAL; |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7b2f6452ba72..f3d4dd580dd6 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -341,13 +341,6 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
341 | 341 | ||
342 | static int instructions_to_print = 16; | 342 | static int instructions_to_print = 16; |
343 | 343 | ||
344 | #ifdef CONFIG_PPC64 | ||
345 | #define BAD_PC(pc) ((REGION_ID(pc) != KERNEL_REGION_ID) && \ | ||
346 | (REGION_ID(pc) != VMALLOC_REGION_ID)) | ||
347 | #else | ||
348 | #define BAD_PC(pc) ((pc) < KERNELBASE) | ||
349 | #endif | ||
350 | |||
351 | static void show_instructions(struct pt_regs *regs) | 344 | static void show_instructions(struct pt_regs *regs) |
352 | { | 345 | { |
353 | int i; | 346 | int i; |
@@ -366,7 +359,8 @@ static void show_instructions(struct pt_regs *regs) | |||
366 | * bad address because the pc *should* only be a | 359 | * bad address because the pc *should* only be a |
367 | * kernel address. | 360 | * kernel address. |
368 | */ | 361 | */ |
369 | if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) { | 362 | if (!__kernel_text_address(pc) || |
363 | __get_user(instr, (unsigned int __user *)pc)) { | ||
370 | printk("XXXXXXXX "); | 364 | printk("XXXXXXXX "); |
371 | } else { | 365 | } else { |
372 | if (regs->nip == pc) | 366 | if (regs->nip == pc) |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 865b9648d0d5..1fc732a552db 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 |
@@ -762,6 +804,56 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) | |||
762 | return of_read_ulong(p, s); | 804 | return of_read_ulong(p, s); |
763 | } | 805 | } |
764 | 806 | ||
807 | #ifdef CONFIG_PPC_PSERIES | ||
808 | /* | ||
809 | * Interpret the ibm,dynamic-memory property in the | ||
810 | * /ibm,dynamic-reconfiguration-memory node. | ||
811 | * This contains a list of memory blocks along with NUMA affinity | ||
812 | * information. | ||
813 | */ | ||
814 | static int __init early_init_dt_scan_drconf_memory(unsigned long node) | ||
815 | { | ||
816 | cell_t *dm, *ls; | ||
817 | unsigned long l, n; | ||
818 | unsigned long base, size, lmb_size, flags; | ||
819 | |||
820 | ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l); | ||
821 | if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t)) | ||
822 | return 0; | ||
823 | lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls); | ||
824 | |||
825 | dm = (cell_t *)of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l); | ||
826 | if (dm == NULL || l < sizeof(cell_t)) | ||
827 | return 0; | ||
828 | |||
829 | n = *dm++; /* number of entries */ | ||
830 | if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t)) | ||
831 | return 0; | ||
832 | |||
833 | for (; n != 0; --n) { | ||
834 | base = dt_mem_next_cell(dt_root_addr_cells, &dm); | ||
835 | flags = dm[3]; | ||
836 | /* skip DRC index, pad, assoc. list index, flags */ | ||
837 | dm += 4; | ||
838 | /* skip this block if the reserved bit is set in flags (0x80) | ||
839 | or if the block is not assigned to this partition (0x8) */ | ||
840 | if ((flags & 0x80) || !(flags & 0x8)) | ||
841 | continue; | ||
842 | size = lmb_size; | ||
843 | if (iommu_is_off) { | ||
844 | if (base >= 0x80000000ul) | ||
845 | continue; | ||
846 | if ((base + size) > 0x80000000ul) | ||
847 | size = 0x80000000ul - base; | ||
848 | } | ||
849 | lmb_add(base, size); | ||
850 | } | ||
851 | lmb_dump_all(); | ||
852 | return 0; | ||
853 | } | ||
854 | #else | ||
855 | #define early_init_dt_scan_drconf_memory(node) 0 | ||
856 | #endif /* CONFIG_PPC_PSERIES */ | ||
765 | 857 | ||
766 | static int __init early_init_dt_scan_memory(unsigned long node, | 858 | static int __init early_init_dt_scan_memory(unsigned long node, |
767 | const char *uname, int depth, void *data) | 859 | const char *uname, int depth, void *data) |
@@ -770,6 +862,11 @@ static int __init early_init_dt_scan_memory(unsigned long node, | |||
770 | cell_t *reg, *endp; | 862 | cell_t *reg, *endp; |
771 | unsigned long l; | 863 | unsigned long l; |
772 | 864 | ||
865 | /* Look for the ibm,dynamic-reconfiguration-memory node */ | ||
866 | if (depth == 1 && | ||
867 | strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) | ||
868 | return early_init_dt_scan_drconf_memory(node); | ||
869 | |||
773 | /* We are scanning "memory" nodes only */ | 870 | /* We are scanning "memory" nodes only */ |
774 | if (type == NULL) { | 871 | if (type == NULL) { |
775 | /* | 872 | /* |
@@ -1014,7 +1111,7 @@ EXPORT_SYMBOL(find_all_nodes); | |||
1014 | /** Checks if the given "compat" string matches one of the strings in | 1111 | /** Checks if the given "compat" string matches one of the strings in |
1015 | * the device's "compatible" property | 1112 | * the device's "compatible" property |
1016 | */ | 1113 | */ |
1017 | int device_is_compatible(struct device_node *device, const char *compat) | 1114 | int device_is_compatible(const struct device_node *device, const char *compat) |
1018 | { | 1115 | { |
1019 | const char* cp; | 1116 | const char* cp; |
1020 | int cplen, l; | 1117 | int cplen, l; |
@@ -1491,7 +1588,8 @@ static int __init prom_reconfig_setup(void) | |||
1491 | __initcall(prom_reconfig_setup); | 1588 | __initcall(prom_reconfig_setup); |
1492 | #endif | 1589 | #endif |
1493 | 1590 | ||
1494 | struct property *of_find_property(struct device_node *np, const char *name, | 1591 | struct property *of_find_property(const struct device_node *np, |
1592 | const char *name, | ||
1495 | int *lenp) | 1593 | int *lenp) |
1496 | { | 1594 | { |
1497 | struct property *pp; | 1595 | struct property *pp; |
@@ -1512,7 +1610,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 | 1610 | * Find a property with a given name for a given node |
1513 | * and return the value. | 1611 | * and return the value. |
1514 | */ | 1612 | */ |
1515 | const void *get_property(struct device_node *np, const char *name, int *lenp) | 1613 | const void *get_property(const struct device_node *np, const char *name, |
1614 | int *lenp) | ||
1516 | { | 1615 | { |
1517 | struct property *pp = of_find_property(np,name,lenp); | 1616 | struct property *pp = of_find_property(np,name,lenp); |
1518 | return pp ? pp->value : NULL; | 1617 | return pp ? pp->value : NULL; |
@@ -1672,6 +1771,7 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) | |||
1672 | } | 1771 | } |
1673 | return NULL; | 1772 | return NULL; |
1674 | } | 1773 | } |
1774 | EXPORT_SYMBOL(of_get_cpu_node); | ||
1675 | 1775 | ||
1676 | #ifdef DEBUG | 1776 | #ifdef DEBUG |
1677 | static struct debugfs_blob_wrapper flat_dt_blob; | 1777 | static struct debugfs_blob_wrapper flat_dt_blob; |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index b91761639d96..520ef42f642e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -173,8 +173,8 @@ static unsigned long __initdata dt_string_start, dt_string_end; | |||
173 | static unsigned long __initdata prom_initrd_start, prom_initrd_end; | 173 | static unsigned long __initdata prom_initrd_start, prom_initrd_end; |
174 | 174 | ||
175 | #ifdef CONFIG_PPC64 | 175 | #ifdef CONFIG_PPC64 |
176 | static int __initdata iommu_force_on; | 176 | static int __initdata prom_iommu_force_on; |
177 | static int __initdata ppc64_iommu_off; | 177 | static int __initdata prom_iommu_off; |
178 | static unsigned long __initdata prom_tce_alloc_start; | 178 | static unsigned long __initdata prom_tce_alloc_start; |
179 | static unsigned long __initdata prom_tce_alloc_end; | 179 | static unsigned long __initdata prom_tce_alloc_end; |
180 | #endif | 180 | #endif |
@@ -582,9 +582,9 @@ static void __init early_cmdline_parse(void) | |||
582 | while (*opt && *opt == ' ') | 582 | while (*opt && *opt == ' ') |
583 | opt++; | 583 | opt++; |
584 | if (!strncmp(opt, RELOC("off"), 3)) | 584 | if (!strncmp(opt, RELOC("off"), 3)) |
585 | RELOC(ppc64_iommu_off) = 1; | 585 | RELOC(prom_iommu_off) = 1; |
586 | else if (!strncmp(opt, RELOC("force"), 5)) | 586 | else if (!strncmp(opt, RELOC("force"), 5)) |
587 | RELOC(iommu_force_on) = 1; | 587 | RELOC(prom_iommu_force_on) = 1; |
588 | } | 588 | } |
589 | #endif | 589 | #endif |
590 | } | 590 | } |
@@ -627,6 +627,7 @@ static void __init early_cmdline_parse(void) | |||
627 | /* Option vector 3: processor options supported */ | 627 | /* Option vector 3: processor options supported */ |
628 | #define OV3_FP 0x80 /* floating point */ | 628 | #define OV3_FP 0x80 /* floating point */ |
629 | #define OV3_VMX 0x40 /* VMX/Altivec */ | 629 | #define OV3_VMX 0x40 /* VMX/Altivec */ |
630 | #define OV3_DFP 0x20 /* decimal FP */ | ||
630 | 631 | ||
631 | /* Option vector 5: PAPR/OF options supported */ | 632 | /* Option vector 5: PAPR/OF options supported */ |
632 | #define OV5_LPAR 0x80 /* logical partitioning supported */ | 633 | #define OV5_LPAR 0x80 /* logical partitioning supported */ |
@@ -642,6 +643,7 @@ static void __init early_cmdline_parse(void) | |||
642 | static unsigned char ibm_architecture_vec[] = { | 643 | static unsigned char ibm_architecture_vec[] = { |
643 | W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ | 644 | W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ |
644 | W(0xffff0000), W(0x003e0000), /* POWER6 */ | 645 | W(0xffff0000), W(0x003e0000), /* POWER6 */ |
646 | W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ | ||
645 | W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ | 647 | W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ |
646 | 5 - 1, /* 5 option vectors */ | 648 | 5 - 1, /* 5 option vectors */ |
647 | 649 | ||
@@ -668,7 +670,7 @@ static unsigned char ibm_architecture_vec[] = { | |||
668 | /* option vector 3: processor options supported */ | 670 | /* option vector 3: processor options supported */ |
669 | 3 - 2, /* length */ | 671 | 3 - 2, /* length */ |
670 | 0, /* don't ignore, don't halt */ | 672 | 0, /* don't ignore, don't halt */ |
671 | OV3_FP | OV3_VMX, | 673 | OV3_FP | OV3_VMX | OV3_DFP, |
672 | 674 | ||
673 | /* option vector 4: IBM PAPR implementation */ | 675 | /* option vector 4: IBM PAPR implementation */ |
674 | 2 - 2, /* length */ | 676 | 2 - 2, /* length */ |
@@ -677,7 +679,7 @@ static unsigned char ibm_architecture_vec[] = { | |||
677 | /* option vector 5: PAPR/OF options */ | 679 | /* option vector 5: PAPR/OF options */ |
678 | 3 - 2, /* length */ | 680 | 3 - 2, /* length */ |
679 | 0, /* don't ignore, don't halt */ | 681 | 0, /* don't ignore, don't halt */ |
680 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES, | 682 | OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY, |
681 | }; | 683 | }; |
682 | 684 | ||
683 | /* Old method - ELF header with PT_NOTE sections */ | 685 | /* Old method - ELF header with PT_NOTE sections */ |
@@ -1167,7 +1169,7 @@ static void __init prom_initialize_tce_table(void) | |||
1167 | u64 local_alloc_top, local_alloc_bottom; | 1169 | u64 local_alloc_top, local_alloc_bottom; |
1168 | u64 i; | 1170 | u64 i; |
1169 | 1171 | ||
1170 | if (RELOC(ppc64_iommu_off)) | 1172 | if (RELOC(prom_iommu_off)) |
1171 | return; | 1173 | return; |
1172 | 1174 | ||
1173 | prom_debug("starting prom_initialize_tce_table\n"); | 1175 | prom_debug("starting prom_initialize_tce_table\n"); |
@@ -2283,11 +2285,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2283 | * Fill in some infos for use by the kernel later on | 2285 | * Fill in some infos for use by the kernel later on |
2284 | */ | 2286 | */ |
2285 | #ifdef CONFIG_PPC64 | 2287 | #ifdef CONFIG_PPC64 |
2286 | if (RELOC(ppc64_iommu_off)) | 2288 | if (RELOC(prom_iommu_off)) |
2287 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", | 2289 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off", |
2288 | NULL, 0); | 2290 | NULL, 0); |
2289 | 2291 | ||
2290 | if (RELOC(iommu_force_on)) | 2292 | if (RELOC(prom_iommu_force_on)) |
2291 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", | 2293 | prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on", |
2292 | NULL, 0); | 2294 | NULL, 0); |
2293 | 2295 | ||
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 603dff3ad62a..0dfbe1cd28eb 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c | |||
@@ -25,6 +25,12 @@ | |||
25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ | 25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ |
26 | (ns) > 0) | 26 | (ns) > 0) |
27 | 27 | ||
28 | static struct of_bus *of_match_bus(struct device_node *np); | ||
29 | static int __of_address_to_resource(struct device_node *dev, | ||
30 | const u32 *addrp, u64 size, unsigned int flags, | ||
31 | struct resource *r); | ||
32 | |||
33 | |||
28 | /* Debug utility */ | 34 | /* Debug utility */ |
29 | #ifdef DEBUG | 35 | #ifdef DEBUG |
30 | static void of_dump_addr(const char *s, const u32 *addr, int na) | 36 | static void of_dump_addr(const char *s, const u32 *addr, int na) |
@@ -101,6 +107,7 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) | |||
101 | } | 107 | } |
102 | 108 | ||
103 | 109 | ||
110 | #ifdef CONFIG_PCI | ||
104 | /* | 111 | /* |
105 | * PCI bus specific translator | 112 | * PCI bus specific translator |
106 | */ | 113 | */ |
@@ -153,15 +160,156 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) | |||
153 | switch((w >> 24) & 0x03) { | 160 | switch((w >> 24) & 0x03) { |
154 | case 0x01: | 161 | case 0x01: |
155 | flags |= IORESOURCE_IO; | 162 | flags |= IORESOURCE_IO; |
163 | break; | ||
156 | case 0x02: /* 32 bits */ | 164 | case 0x02: /* 32 bits */ |
157 | case 0x03: /* 64 bits */ | 165 | case 0x03: /* 64 bits */ |
158 | flags |= IORESOURCE_MEM; | 166 | flags |= IORESOURCE_MEM; |
167 | break; | ||
159 | } | 168 | } |
160 | if (w & 0x40000000) | 169 | if (w & 0x40000000) |
161 | flags |= IORESOURCE_PREFETCH; | 170 | flags |= IORESOURCE_PREFETCH; |
162 | return flags; | 171 | return flags; |
163 | } | 172 | } |
164 | 173 | ||
174 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
175 | unsigned int *flags) | ||
176 | { | ||
177 | const u32 *prop; | ||
178 | unsigned int psize; | ||
179 | struct device_node *parent; | ||
180 | struct of_bus *bus; | ||
181 | int onesize, i, na, ns; | ||
182 | |||
183 | /* Get parent & match bus type */ | ||
184 | parent = of_get_parent(dev); | ||
185 | if (parent == NULL) | ||
186 | return NULL; | ||
187 | bus = of_match_bus(parent); | ||
188 | if (strcmp(bus->name, "pci")) { | ||
189 | of_node_put(parent); | ||
190 | return NULL; | ||
191 | } | ||
192 | bus->count_cells(dev, &na, &ns); | ||
193 | of_node_put(parent); | ||
194 | if (!OF_CHECK_COUNTS(na, ns)) | ||
195 | return NULL; | ||
196 | |||
197 | /* Get "reg" or "assigned-addresses" property */ | ||
198 | prop = get_property(dev, bus->addresses, &psize); | ||
199 | if (prop == NULL) | ||
200 | return NULL; | ||
201 | psize /= 4; | ||
202 | |||
203 | onesize = na + ns; | ||
204 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
205 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
206 | if (size) | ||
207 | *size = of_read_number(prop + na, ns); | ||
208 | if (flags) | ||
209 | *flags = bus->get_flags(prop); | ||
210 | return prop; | ||
211 | } | ||
212 | return NULL; | ||
213 | } | ||
214 | EXPORT_SYMBOL(of_get_pci_address); | ||
215 | |||
216 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
217 | struct resource *r) | ||
218 | { | ||
219 | const u32 *addrp; | ||
220 | u64 size; | ||
221 | unsigned int flags; | ||
222 | |||
223 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
224 | if (addrp == NULL) | ||
225 | return -EINVAL; | ||
226 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
227 | } | ||
228 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
229 | |||
230 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
231 | { | ||
232 | return (((pin - 1) + slot) % 4) + 1; | ||
233 | } | ||
234 | |||
235 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
236 | { | ||
237 | struct device_node *dn, *ppnode; | ||
238 | struct pci_dev *ppdev; | ||
239 | u32 lspec; | ||
240 | u32 laddr[3]; | ||
241 | u8 pin; | ||
242 | int rc; | ||
243 | |||
244 | /* Check if we have a device node, if yes, fallback to standard OF | ||
245 | * parsing | ||
246 | */ | ||
247 | dn = pci_device_to_OF_node(pdev); | ||
248 | if (dn) | ||
249 | return of_irq_map_one(dn, 0, out_irq); | ||
250 | |||
251 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
252 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
253 | * for PCI. If you do different, then don't use that routine. | ||
254 | */ | ||
255 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
256 | if (rc != 0) | ||
257 | return rc; | ||
258 | /* No pin, exit */ | ||
259 | if (pin == 0) | ||
260 | return -ENODEV; | ||
261 | |||
262 | /* Now we walk up the PCI tree */ | ||
263 | lspec = pin; | ||
264 | for (;;) { | ||
265 | /* Get the pci_dev of our parent */ | ||
266 | ppdev = pdev->bus->self; | ||
267 | |||
268 | /* Ouch, it's a host bridge... */ | ||
269 | if (ppdev == NULL) { | ||
270 | #ifdef CONFIG_PPC64 | ||
271 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
272 | #else | ||
273 | struct pci_controller *host; | ||
274 | host = pci_bus_to_host(pdev->bus); | ||
275 | ppnode = host ? host->arch_data : NULL; | ||
276 | #endif | ||
277 | /* No node for host bridge ? give up */ | ||
278 | if (ppnode == NULL) | ||
279 | return -EINVAL; | ||
280 | } else | ||
281 | /* We found a P2P bridge, check if it has a node */ | ||
282 | ppnode = pci_device_to_OF_node(ppdev); | ||
283 | |||
284 | /* Ok, we have found a parent with a device-node, hand over to | ||
285 | * the OF parsing code. | ||
286 | * We build a unit address from the linux device to be used for | ||
287 | * resolution. Note that we use the linux bus number which may | ||
288 | * not match your firmware bus numbering. | ||
289 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
290 | * the bus number as part of the matching. | ||
291 | * You should still be careful about that though if you intend | ||
292 | * to rely on this function (you ship a firmware that doesn't | ||
293 | * create device nodes for all PCI devices). | ||
294 | */ | ||
295 | if (ppnode) | ||
296 | break; | ||
297 | |||
298 | /* We can only get here if we hit a P2P bridge with no node, | ||
299 | * let's do standard swizzling and try again | ||
300 | */ | ||
301 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
302 | pdev = ppdev; | ||
303 | } | ||
304 | |||
305 | laddr[0] = (pdev->bus->number << 16) | ||
306 | | (pdev->devfn << 8); | ||
307 | laddr[1] = laddr[2] = 0; | ||
308 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
309 | } | ||
310 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
311 | #endif /* CONFIG_PCI */ | ||
312 | |||
165 | /* | 313 | /* |
166 | * ISA bus specific translator | 314 | * ISA bus specific translator |
167 | */ | 315 | */ |
@@ -223,6 +371,7 @@ static unsigned int of_bus_isa_get_flags(const u32 *addr) | |||
223 | */ | 371 | */ |
224 | 372 | ||
225 | static struct of_bus of_busses[] = { | 373 | static struct of_bus of_busses[] = { |
374 | #ifdef CONFIG_PCI | ||
226 | /* PCI */ | 375 | /* PCI */ |
227 | { | 376 | { |
228 | .name = "pci", | 377 | .name = "pci", |
@@ -233,6 +382,7 @@ static struct of_bus of_busses[] = { | |||
233 | .translate = of_bus_pci_translate, | 382 | .translate = of_bus_pci_translate, |
234 | .get_flags = of_bus_pci_get_flags, | 383 | .get_flags = of_bus_pci_get_flags, |
235 | }, | 384 | }, |
385 | #endif /* CONFIG_PCI */ | ||
236 | /* ISA */ | 386 | /* ISA */ |
237 | { | 387 | { |
238 | .name = "isa", | 388 | .name = "isa", |
@@ -445,48 +595,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, | |||
445 | } | 595 | } |
446 | EXPORT_SYMBOL(of_get_address); | 596 | EXPORT_SYMBOL(of_get_address); |
447 | 597 | ||
448 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
449 | unsigned int *flags) | ||
450 | { | ||
451 | const u32 *prop; | ||
452 | unsigned int psize; | ||
453 | struct device_node *parent; | ||
454 | struct of_bus *bus; | ||
455 | int onesize, i, na, ns; | ||
456 | |||
457 | /* Get parent & match bus type */ | ||
458 | parent = of_get_parent(dev); | ||
459 | if (parent == NULL) | ||
460 | return NULL; | ||
461 | bus = of_match_bus(parent); | ||
462 | if (strcmp(bus->name, "pci")) { | ||
463 | of_node_put(parent); | ||
464 | return NULL; | ||
465 | } | ||
466 | bus->count_cells(dev, &na, &ns); | ||
467 | of_node_put(parent); | ||
468 | if (!OF_CHECK_COUNTS(na, ns)) | ||
469 | return NULL; | ||
470 | |||
471 | /* Get "reg" or "assigned-addresses" property */ | ||
472 | prop = get_property(dev, bus->addresses, &psize); | ||
473 | if (prop == NULL) | ||
474 | return NULL; | ||
475 | psize /= 4; | ||
476 | |||
477 | onesize = na + ns; | ||
478 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
479 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
480 | if (size) | ||
481 | *size = of_read_number(prop + na, ns); | ||
482 | if (flags) | ||
483 | *flags = bus->get_flags(prop); | ||
484 | return prop; | ||
485 | } | ||
486 | return NULL; | ||
487 | } | ||
488 | EXPORT_SYMBOL(of_get_pci_address); | ||
489 | |||
490 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, | 598 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, |
491 | u64 size, unsigned int flags, | 599 | u64 size, unsigned int flags, |
492 | struct resource *r) | 600 | struct resource *r) |
@@ -529,20 +637,6 @@ int of_address_to_resource(struct device_node *dev, int index, | |||
529 | } | 637 | } |
530 | EXPORT_SYMBOL_GPL(of_address_to_resource); | 638 | EXPORT_SYMBOL_GPL(of_address_to_resource); |
531 | 639 | ||
532 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
533 | struct resource *r) | ||
534 | { | ||
535 | const u32 *addrp; | ||
536 | u64 size; | ||
537 | unsigned int flags; | ||
538 | |||
539 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
540 | if (addrp == NULL) | ||
541 | return -EINVAL; | ||
542 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
543 | } | ||
544 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
545 | |||
546 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, | 640 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, |
547 | unsigned long *busno, unsigned long *phys, unsigned long *size) | 641 | unsigned long *busno, unsigned long *phys, unsigned long *size) |
548 | { | 642 | { |
@@ -898,87 +992,3 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq | |||
898 | return res; | 992 | return res; |
899 | } | 993 | } |
900 | EXPORT_SYMBOL_GPL(of_irq_map_one); | 994 | EXPORT_SYMBOL_GPL(of_irq_map_one); |
901 | |||
902 | #ifdef CONFIG_PCI | ||
903 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
904 | { | ||
905 | return (((pin - 1) + slot) % 4) + 1; | ||
906 | } | ||
907 | |||
908 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
909 | { | ||
910 | struct device_node *dn, *ppnode; | ||
911 | struct pci_dev *ppdev; | ||
912 | u32 lspec; | ||
913 | u32 laddr[3]; | ||
914 | u8 pin; | ||
915 | int rc; | ||
916 | |||
917 | /* Check if we have a device node, if yes, fallback to standard OF | ||
918 | * parsing | ||
919 | */ | ||
920 | dn = pci_device_to_OF_node(pdev); | ||
921 | if (dn) | ||
922 | return of_irq_map_one(dn, 0, out_irq); | ||
923 | |||
924 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
925 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
926 | * for PCI. If you do different, then don't use that routine. | ||
927 | */ | ||
928 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
929 | if (rc != 0) | ||
930 | return rc; | ||
931 | /* No pin, exit */ | ||
932 | if (pin == 0) | ||
933 | return -ENODEV; | ||
934 | |||
935 | /* Now we walk up the PCI tree */ | ||
936 | lspec = pin; | ||
937 | for (;;) { | ||
938 | /* Get the pci_dev of our parent */ | ||
939 | ppdev = pdev->bus->self; | ||
940 | |||
941 | /* Ouch, it's a host bridge... */ | ||
942 | if (ppdev == NULL) { | ||
943 | #ifdef CONFIG_PPC64 | ||
944 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
945 | #else | ||
946 | struct pci_controller *host; | ||
947 | host = pci_bus_to_host(pdev->bus); | ||
948 | ppnode = host ? host->arch_data : NULL; | ||
949 | #endif | ||
950 | /* No node for host bridge ? give up */ | ||
951 | if (ppnode == NULL) | ||
952 | return -EINVAL; | ||
953 | } else | ||
954 | /* We found a P2P bridge, check if it has a node */ | ||
955 | ppnode = pci_device_to_OF_node(ppdev); | ||
956 | |||
957 | /* Ok, we have found a parent with a device-node, hand over to | ||
958 | * the OF parsing code. | ||
959 | * We build a unit address from the linux device to be used for | ||
960 | * resolution. Note that we use the linux bus number which may | ||
961 | * not match your firmware bus numbering. | ||
962 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
963 | * the bus number as part of the matching. | ||
964 | * You should still be careful about that though if you intend | ||
965 | * to rely on this function (you ship a firmware that doesn't | ||
966 | * create device nodes for all PCI devices). | ||
967 | */ | ||
968 | if (ppnode) | ||
969 | break; | ||
970 | |||
971 | /* We can only get here if we hit a P2P bridge with no node, | ||
972 | * let's do standard swizzling and try again | ||
973 | */ | ||
974 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
975 | pdev = ppdev; | ||
976 | } | ||
977 | |||
978 | laddr[0] = (pdev->bus->number << 16) | ||
979 | | (pdev->devfn << 8); | ||
980 | laddr[1] = laddr[2] = 0; | ||
981 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
982 | } | ||
983 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
984 | #endif /* CONFIG_PCI */ | ||
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 6ef80d4e38d3..76b5d7ebdcc6 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -303,6 +303,12 @@ int rtas_token(const char *service) | |||
303 | } | 303 | } |
304 | EXPORT_SYMBOL(rtas_token); | 304 | EXPORT_SYMBOL(rtas_token); |
305 | 305 | ||
306 | int rtas_service_present(const char *service) | ||
307 | { | ||
308 | return rtas_token(service) != RTAS_UNKNOWN_SERVICE; | ||
309 | } | ||
310 | EXPORT_SYMBOL(rtas_service_present); | ||
311 | |||
306 | #ifdef CONFIG_RTAS_ERROR_LOGGING | 312 | #ifdef CONFIG_RTAS_ERROR_LOGGING |
307 | /* | 313 | /* |
308 | * Return the firmware-specified size of the error log buffer | 314 | * Return the firmware-specified size of the error log buffer |
@@ -810,31 +816,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) | |||
810 | return 0; | 816 | return 0; |
811 | } | 817 | } |
812 | 818 | ||
813 | /* This version can't take the spinlock, because it never returns */ | ||
814 | |||
815 | struct rtas_args rtas_stop_self_args = { | ||
816 | /* The token is initialized for real in setup_system() */ | ||
817 | .token = RTAS_UNKNOWN_SERVICE, | ||
818 | .nargs = 0, | ||
819 | .nret = 1, | ||
820 | .rets = &rtas_stop_self_args.args[0], | ||
821 | }; | ||
822 | |||
823 | void rtas_stop_self(void) | ||
824 | { | ||
825 | struct rtas_args *rtas_args = &rtas_stop_self_args; | ||
826 | |||
827 | local_irq_disable(); | ||
828 | |||
829 | BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE); | ||
830 | |||
831 | printk("cpu %u (hwid %u) Ready to die...\n", | ||
832 | smp_processor_id(), hard_smp_processor_id()); | ||
833 | enter_rtas(__pa(rtas_args)); | ||
834 | |||
835 | panic("Alas, I survived.\n"); | ||
836 | } | ||
837 | |||
838 | /* | 819 | /* |
839 | * Call early during boot, before mem init or bootmem, to retrieve the RTAS | 820 | * Call early during boot, before mem init or bootmem, to retrieve the RTAS |
840 | * informations from the device-tree and allocate the RMO buffer for userland | 821 | * informations from the device-tree and allocate the RMO buffer for userland |
@@ -879,9 +860,6 @@ void __init rtas_initialize(void) | |||
879 | #endif | 860 | #endif |
880 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); | 861 | rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region); |
881 | 862 | ||
882 | #ifdef CONFIG_HOTPLUG_CPU | ||
883 | rtas_stop_self_args.token = rtas_token("stop-self"); | ||
884 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
885 | #ifdef CONFIG_RTAS_ERROR_LOGGING | 863 | #ifdef CONFIG_RTAS_ERROR_LOGGING |
886 | rtas_last_error_token = rtas_token("rtas-last-error"); | 864 | rtas_last_error_token = rtas_token("rtas-last-error"); |
887 | #endif | 865 | #endif |
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 1442b63a75da..0c4fcd34bfe5 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 struct kmem_cache *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,16 +184,16 @@ 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 | } |
186 | 193 | ||
187 | static int rtas_flash_release(struct inode *inode, struct file *file) | 194 | static int rtas_flash_release(struct inode *inode, struct file *file) |
188 | { | 195 | { |
189 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 196 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
190 | struct rtas_update_flash_t *uf; | 197 | struct rtas_update_flash_t *uf; |
191 | 198 | ||
192 | uf = (struct rtas_update_flash_t *) dp->data; | 199 | uf = (struct rtas_update_flash_t *) dp->data; |
@@ -248,7 +255,7 @@ static void get_flash_status_msg(int status, char *buf) | |||
248 | static ssize_t rtas_flash_read(struct file *file, char __user *buf, | 255 | static ssize_t rtas_flash_read(struct file *file, char __user *buf, |
249 | size_t count, loff_t *ppos) | 256 | size_t count, loff_t *ppos) |
250 | { | 257 | { |
251 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 258 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
252 | struct rtas_update_flash_t *uf; | 259 | struct rtas_update_flash_t *uf; |
253 | char msg[RTAS_MSG_MAXLEN]; | 260 | char msg[RTAS_MSG_MAXLEN]; |
254 | int msglen; | 261 | int msglen; |
@@ -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, struct kmem_cache *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 |
@@ -286,7 +299,7 @@ static ssize_t rtas_flash_read(struct file *file, char __user *buf, | |||
286 | static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, | 299 | static ssize_t rtas_flash_write(struct file *file, const char __user *buffer, |
287 | size_t count, loff_t *off) | 300 | size_t count, loff_t *off) |
288 | { | 301 | { |
289 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 302 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
290 | struct rtas_update_flash_t *uf; | 303 | struct rtas_update_flash_t *uf; |
291 | char *p; | 304 | char *p; |
292 | int next_free; | 305 | int next_free; |
@@ -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; |
@@ -378,7 +391,7 @@ static void manage_flash(struct rtas_manage_flash_t *args_buf) | |||
378 | static ssize_t manage_flash_read(struct file *file, char __user *buf, | 391 | static ssize_t manage_flash_read(struct file *file, char __user *buf, |
379 | size_t count, loff_t *ppos) | 392 | size_t count, loff_t *ppos) |
380 | { | 393 | { |
381 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 394 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
382 | struct rtas_manage_flash_t *args_buf; | 395 | struct rtas_manage_flash_t *args_buf; |
383 | char msg[RTAS_MSG_MAXLEN]; | 396 | char msg[RTAS_MSG_MAXLEN]; |
384 | int msglen; | 397 | int msglen; |
@@ -408,7 +421,7 @@ static ssize_t manage_flash_read(struct file *file, char __user *buf, | |||
408 | static ssize_t manage_flash_write(struct file *file, const char __user *buf, | 421 | static ssize_t manage_flash_write(struct file *file, const char __user *buf, |
409 | size_t count, loff_t *off) | 422 | size_t count, loff_t *off) |
410 | { | 423 | { |
411 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 424 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
412 | struct rtas_manage_flash_t *args_buf; | 425 | struct rtas_manage_flash_t *args_buf; |
413 | const char reject_str[] = "0"; | 426 | const char reject_str[] = "0"; |
414 | const char commit_str[] = "1"; | 427 | const char commit_str[] = "1"; |
@@ -479,7 +492,7 @@ static int get_validate_flash_msg(struct rtas_validate_flash_t *args_buf, | |||
479 | static ssize_t validate_flash_read(struct file *file, char __user *buf, | 492 | static ssize_t validate_flash_read(struct file *file, char __user *buf, |
480 | size_t count, loff_t *ppos) | 493 | size_t count, loff_t *ppos) |
481 | { | 494 | { |
482 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 495 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
483 | struct rtas_validate_flash_t *args_buf; | 496 | struct rtas_validate_flash_t *args_buf; |
484 | char msg[RTAS_MSG_MAXLEN]; | 497 | char msg[RTAS_MSG_MAXLEN]; |
485 | int msglen; | 498 | int msglen; |
@@ -507,7 +520,7 @@ static ssize_t validate_flash_read(struct file *file, char __user *buf, | |||
507 | static ssize_t validate_flash_write(struct file *file, const char __user *buf, | 520 | static ssize_t validate_flash_write(struct file *file, const char __user *buf, |
508 | size_t count, loff_t *off) | 521 | size_t count, loff_t *off) |
509 | { | 522 | { |
510 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 523 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
511 | struct rtas_validate_flash_t *args_buf; | 524 | struct rtas_validate_flash_t *args_buf; |
512 | int rc; | 525 | int rc; |
513 | 526 | ||
@@ -556,7 +569,7 @@ done: | |||
556 | 569 | ||
557 | static int validate_flash_release(struct inode *inode, struct file *file) | 570 | static int validate_flash_release(struct inode *inode, struct file *file) |
558 | { | 571 | { |
559 | struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); | 572 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); |
560 | struct rtas_validate_flash_t *args_buf; | 573 | struct rtas_validate_flash_t *args_buf; |
561 | 574 | ||
562 | args_buf = (struct rtas_validate_flash_t *) dp->data; | 575 | args_buf = (struct rtas_validate_flash_t *) dp->data; |
@@ -668,14 +681,12 @@ static int initialize_flash_pde_data(const char *rtas_call_name, | |||
668 | int *status; | 681 | int *status; |
669 | int token; | 682 | int token; |
670 | 683 | ||
671 | dp->data = kmalloc(buf_size, GFP_KERNEL); | 684 | dp->data = kzalloc(buf_size, GFP_KERNEL); |
672 | if (dp->data == NULL) { | 685 | if (dp->data == NULL) { |
673 | remove_flash_pde(dp); | 686 | remove_flash_pde(dp); |
674 | return -ENOMEM; | 687 | return -ENOMEM; |
675 | } | 688 | } |
676 | 689 | ||
677 | memset(dp->data, 0, buf_size); | ||
678 | |||
679 | /* | 690 | /* |
680 | * This code assumes that the status int is the first member of the | 691 | * This code assumes that the status int is the first member of the |
681 | * struct | 692 | * struct |
@@ -791,6 +802,16 @@ int __init rtas_flash_init(void) | |||
791 | goto cleanup; | 802 | goto cleanup; |
792 | 803 | ||
793 | rtas_flash_term_hook = rtas_flash_firmware; | 804 | rtas_flash_term_hook = rtas_flash_firmware; |
805 | |||
806 | flash_block_cache = kmem_cache_create("rtas_flash_cache", | ||
807 | RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0, | ||
808 | rtas_block_ctor, NULL); | ||
809 | if (!flash_block_cache) { | ||
810 | printk(KERN_ERR "%s: failed to create block cache\n", | ||
811 | __FUNCTION__); | ||
812 | rc = -ENOMEM; | ||
813 | goto cleanup; | ||
814 | } | ||
794 | return 0; | 815 | return 0; |
795 | 816 | ||
796 | cleanup: | 817 | cleanup: |
@@ -805,6 +826,10 @@ cleanup: | |||
805 | void __exit rtas_flash_cleanup(void) | 826 | void __exit rtas_flash_cleanup(void) |
806 | { | 827 | { |
807 | rtas_flash_term_hook = NULL; | 828 | rtas_flash_term_hook = NULL; |
829 | |||
830 | if (flash_block_cache) | ||
831 | kmem_cache_destroy(flash_block_cache); | ||
832 | |||
808 | remove_flash_pde(firmware_flash_pde); | 833 | remove_flash_pde(firmware_flash_pde); |
809 | remove_flash_pde(firmware_update_pde); | 834 | remove_flash_pde(firmware_update_pde); |
810 | remove_flash_pde(validate_pde); | 835 | remove_flash_pde(validate_pde); |
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index b4a0de79c060..ace9f4c86e67 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <asm/rtas.h> | 38 | #include <asm/rtas.h> |
39 | #include <asm/mpic.h> | 39 | #include <asm/mpic.h> |
40 | #include <asm/ppc-pci.h> | 40 | #include <asm/ppc-pci.h> |
41 | #include <asm/eeh.h> | ||
41 | 42 | ||
42 | /* RTAS tokens */ | 43 | /* RTAS tokens */ |
43 | static int read_pci_config; | 44 | static int read_pci_config; |
@@ -231,32 +232,13 @@ void __init init_pci_config_tokens (void) | |||
231 | 232 | ||
232 | unsigned long __devinit get_phb_buid (struct device_node *phb) | 233 | unsigned long __devinit get_phb_buid (struct device_node *phb) |
233 | { | 234 | { |
234 | int addr_cells; | 235 | struct resource r; |
235 | const unsigned int *buid_vals; | ||
236 | unsigned int len; | ||
237 | unsigned long buid; | ||
238 | |||
239 | if (ibm_read_pci_config == -1) return 0; | ||
240 | 236 | ||
241 | /* PHB's will always be children of the root node, | 237 | if (ibm_read_pci_config == -1) |
242 | * or so it is promised by the current firmware. */ | ||
243 | if (phb->parent == NULL) | ||
244 | return 0; | 238 | return 0; |
245 | if (phb->parent->parent) | 239 | if (of_address_to_resource(phb, 0, &r)) |
246 | return 0; | ||
247 | |||
248 | buid_vals = get_property(phb, "reg", &len); | ||
249 | if (buid_vals == NULL) | ||
250 | return 0; | 240 | return 0; |
251 | 241 | return r.start; | |
252 | addr_cells = prom_n_addr_cells(phb); | ||
253 | if (addr_cells == 1) { | ||
254 | buid = (unsigned long) buid_vals[0]; | ||
255 | } else { | ||
256 | buid = (((unsigned long)buid_vals[0]) << 32UL) | | ||
257 | (((unsigned long)buid_vals[1]) & 0xffffffff); | ||
258 | } | ||
259 | return buid; | ||
260 | } | 242 | } |
261 | 243 | ||
262 | static int phb_set_bus_ranges(struct device_node *dev, | 244 | static int phb_set_bus_ranges(struct device_node *dev, |
@@ -276,8 +258,10 @@ static int phb_set_bus_ranges(struct device_node *dev, | |||
276 | return 0; | 258 | return 0; |
277 | } | 259 | } |
278 | 260 | ||
279 | int __devinit setup_phb(struct device_node *dev, struct pci_controller *phb) | 261 | int __devinit rtas_setup_phb(struct pci_controller *phb) |
280 | { | 262 | { |
263 | struct device_node *dev = phb->arch_data; | ||
264 | |||
281 | if (is_python(dev)) | 265 | if (is_python(dev)) |
282 | python_countermeasures(dev); | 266 | python_countermeasures(dev); |
283 | 267 | ||
@@ -309,7 +293,7 @@ unsigned long __init find_and_init_phbs(void) | |||
309 | phb = pcibios_alloc_controller(node); | 293 | phb = pcibios_alloc_controller(node); |
310 | if (!phb) | 294 | if (!phb) |
311 | continue; | 295 | continue; |
312 | setup_phb(node, phb); | 296 | rtas_setup_phb(phb); |
313 | pci_process_bridge_OF_ranges(phb, node, 0); | 297 | pci_process_bridge_OF_ranges(phb, node, 0); |
314 | pci_setup_phb_io(phb, index == 0); | 298 | pci_setup_phb_io(phb, index == 0); |
315 | index++; | 299 | index++; |
@@ -381,7 +365,6 @@ int pcibios_remove_root_bus(struct pci_controller *phb) | |||
381 | } | 365 | } |
382 | } | 366 | } |
383 | 367 | ||
384 | list_del(&phb->list_node); | ||
385 | pcibios_free_controller(phb); | 368 | pcibios_free_controller(phb); |
386 | 369 | ||
387 | return 0; | 370 | return 0; |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 191d0ab09222..61c65d19ef06 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -63,10 +63,6 @@ unsigned int DMA_MODE_WRITE; | |||
63 | 63 | ||
64 | int have_of = 1; | 64 | int have_of = 1; |
65 | 65 | ||
66 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
67 | dev_t boot_dev; | ||
68 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
69 | |||
70 | #ifdef CONFIG_VGA_CONSOLE | 66 | #ifdef CONFIG_VGA_CONSOLE |
71 | unsigned long vgacon_remap_base; | 67 | unsigned long vgacon_remap_base; |
72 | #endif | 68 | #endif |
@@ -91,6 +87,7 @@ int ucache_bsize; | |||
91 | unsigned long __init early_init(unsigned long dt_ptr) | 87 | unsigned long __init early_init(unsigned long dt_ptr) |
92 | { | 88 | { |
93 | unsigned long offset = reloc_offset(); | 89 | unsigned long offset = reloc_offset(); |
90 | struct cpu_spec *spec; | ||
94 | 91 | ||
95 | /* First zero the BSS -- use memset_io, some platforms don't have | 92 | /* First zero the BSS -- use memset_io, some platforms don't have |
96 | * caches on yet */ | 93 | * caches on yet */ |
@@ -100,8 +97,11 @@ unsigned long __init early_init(unsigned long dt_ptr) | |||
100 | * Identify the CPU type and fix up code sections | 97 | * Identify the CPU type and fix up code sections |
101 | * that depend on which cpu we have. | 98 | * that depend on which cpu we have. |
102 | */ | 99 | */ |
103 | identify_cpu(offset, 0); | 100 | spec = identify_cpu(offset, mfspr(SPRN_PVR)); |
104 | do_cpu_ftr_fixups(offset); | 101 | |
102 | do_feature_fixups(spec->cpu_features, | ||
103 | PTRRELOC(&__start___ftr_fixup), | ||
104 | PTRRELOC(&__stop___ftr_fixup)); | ||
105 | 105 | ||
106 | return KERNELBASE + offset; | 106 | return KERNELBASE + offset; |
107 | } | 107 | } |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 4b2e32eab9dc..3733de30e84d 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/serial.h> | 33 | #include <linux/serial.h> |
34 | #include <linux/serial_8250.h> | 34 | #include <linux/serial_8250.h> |
35 | #include <linux/bootmem.h> | 35 | #include <linux/bootmem.h> |
36 | #include <linux/pci.h> | ||
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
37 | #include <asm/kdump.h> | 38 | #include <asm/kdump.h> |
38 | #include <asm/prom.h> | 39 | #include <asm/prom.h> |
@@ -71,7 +72,6 @@ | |||
71 | 72 | ||
72 | int have_of = 1; | 73 | int have_of = 1; |
73 | int boot_cpuid = 0; | 74 | int boot_cpuid = 0; |
74 | dev_t boot_dev; | ||
75 | u64 ppc64_pft_size; | 75 | u64 ppc64_pft_size; |
76 | 76 | ||
77 | /* Pick defaults since we might want to patch instructions | 77 | /* Pick defaults since we might want to patch instructions |
@@ -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, mfspr(SPRN_PVR)); | ||
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 | ||
@@ -223,8 +226,8 @@ void early_setup_secondary(void) | |||
223 | { | 226 | { |
224 | struct paca_struct *lpaca = get_paca(); | 227 | struct paca_struct *lpaca = get_paca(); |
225 | 228 | ||
226 | /* Mark enabled in PACA */ | 229 | /* Mark interrupts enabled in PACA */ |
227 | lpaca->proc_enabled = 0; | 230 | lpaca->soft_enabled = 0; |
228 | 231 | ||
229 | /* Initialize hash table for that CPU */ | 232 | /* Initialize hash table for that CPU */ |
230 | htab_initialize_secondary(); | 233 | htab_initialize_secondary(); |
@@ -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 | */ |
@@ -381,7 +392,8 @@ void __init setup_system(void) | |||
381 | * setting up the hash table pointers. It also sets up some interrupt-mapping | 392 | * setting up the hash table pointers. It also sets up some interrupt-mapping |
382 | * related options that will be used by finish_device_tree() | 393 | * related options that will be used by finish_device_tree() |
383 | */ | 394 | */ |
384 | ppc_md.init_early(); | 395 | if (ppc_md.init_early) |
396 | ppc_md.init_early(); | ||
385 | 397 | ||
386 | /* | 398 | /* |
387 | * We can discover serial ports now since the above did setup the | 399 | * We can discover serial ports now since the above did setup the |
@@ -587,3 +599,10 @@ void __init setup_per_cpu_areas(void) | |||
587 | } | 599 | } |
588 | } | 600 | } |
589 | #endif | 601 | #endif |
602 | |||
603 | |||
604 | #ifdef CONFIG_PPC_INDIRECT_IO | ||
605 | struct ppc_pci_io ppc_pci_io; | ||
606 | EXPORT_SYMBOL(ppc_pci_io); | ||
607 | #endif /* CONFIG_PPC_INDIRECT_IO */ | ||
608 | |||
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 320353f0926f..e4ebe1a6228e 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include <linux/stddef.h> | 36 | #include <linux/stddef.h> |
37 | #include <linux/tty.h> | 37 | #include <linux/tty.h> |
38 | #include <linux/binfmts.h> | 38 | #include <linux/binfmts.h> |
39 | #include <linux/suspend.h> | 39 | #include <linux/freezer.h> |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
diff --git a/arch/powerpc/kernel/smp-tbsync.c b/arch/powerpc/kernel/smp-tbsync.c index de59c6c31a5b..bc892e69b4f7 100644 --- a/arch/powerpc/kernel/smp-tbsync.c +++ b/arch/powerpc/kernel/smp-tbsync.c | |||
@@ -78,7 +78,7 @@ static int __devinit start_contest(int cmd, long offset, int num) | |||
78 | { | 78 | { |
79 | int i, score=0; | 79 | int i, score=0; |
80 | u64 tb; | 80 | u64 tb; |
81 | long mark; | 81 | u64 mark; |
82 | 82 | ||
83 | tbsync->cmd = cmd; | 83 | tbsync->cmd = cmd; |
84 | 84 | ||
@@ -116,8 +116,7 @@ void __devinit smp_generic_give_timebase(void) | |||
116 | printk("Synchronizing timebase\n"); | 116 | printk("Synchronizing timebase\n"); |
117 | 117 | ||
118 | /* if this fails then this kernel won't work anyway... */ | 118 | /* if this fails then this kernel won't work anyway... */ |
119 | tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL ); | 119 | tbsync = kzalloc( sizeof(*tbsync), GFP_KERNEL ); |
120 | memset( tbsync, 0, sizeof(*tbsync) ); | ||
121 | mb(); | 120 | mb(); |
122 | running = 1; | 121 | running = 1; |
123 | 122 | ||
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 35c6309bdb76..9b28c238b6c0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -65,6 +65,7 @@ cpumask_t cpu_sibling_map[NR_CPUS] = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; | |||
65 | 65 | ||
66 | EXPORT_SYMBOL(cpu_online_map); | 66 | EXPORT_SYMBOL(cpu_online_map); |
67 | EXPORT_SYMBOL(cpu_possible_map); | 67 | EXPORT_SYMBOL(cpu_possible_map); |
68 | EXPORT_SYMBOL(cpu_sibling_map); | ||
68 | 69 | ||
69 | /* SMP operations for this machine */ | 70 | /* SMP operations for this machine */ |
70 | struct smp_ops_t *smp_ops; | 71 | struct smp_ops_t *smp_ops; |
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index d15c33e95959..03a2a2f30d66 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <asm/time.h> | 51 | #include <asm/time.h> |
52 | #include <asm/mmu_context.h> | 52 | #include <asm/mmu_context.h> |
53 | #include <asm/ppc-pci.h> | 53 | #include <asm/ppc-pci.h> |
54 | #include <asm/syscalls.h> | ||
54 | 55 | ||
55 | /* readdir & getdents */ | 56 | /* readdir & getdents */ |
56 | #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) | 57 | #define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de))) |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index d45a168bdaca..400ab2b946e7 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -181,6 +181,8 @@ SYSFS_PMCSETUP(pmc6, SPRN_PMC6); | |||
181 | SYSFS_PMCSETUP(pmc7, SPRN_PMC7); | 181 | SYSFS_PMCSETUP(pmc7, SPRN_PMC7); |
182 | SYSFS_PMCSETUP(pmc8, SPRN_PMC8); | 182 | SYSFS_PMCSETUP(pmc8, SPRN_PMC8); |
183 | SYSFS_PMCSETUP(purr, SPRN_PURR); | 183 | SYSFS_PMCSETUP(purr, SPRN_PURR); |
184 | SYSFS_PMCSETUP(spurr, SPRN_SPURR); | ||
185 | SYSFS_PMCSETUP(dscr, SPRN_DSCR); | ||
184 | 186 | ||
185 | static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0); | 187 | static SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0); |
186 | static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1); | 188 | static SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1); |
@@ -194,16 +196,17 @@ static SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6); | |||
194 | static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7); | 196 | static SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7); |
195 | static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8); | 197 | static SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8); |
196 | static SYSDEV_ATTR(purr, 0600, show_purr, NULL); | 198 | static SYSDEV_ATTR(purr, 0600, show_purr, NULL); |
199 | static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL); | ||
200 | static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr); | ||
197 | 201 | ||
198 | static void register_cpu_online(unsigned int cpu) | 202 | static void register_cpu_online(unsigned int cpu) |
199 | { | 203 | { |
200 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 204 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
201 | struct sys_device *s = &c->sysdev; | 205 | struct sys_device *s = &c->sysdev; |
202 | 206 | ||
203 | #ifndef CONFIG_PPC_ISERIES | 207 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && |
204 | if (cpu_has_feature(CPU_FTR_SMT)) | 208 | cpu_has_feature(CPU_FTR_SMT)) |
205 | sysdev_create_file(s, &attr_smt_snooze_delay); | 209 | sysdev_create_file(s, &attr_smt_snooze_delay); |
206 | #endif | ||
207 | 210 | ||
208 | /* PMC stuff */ | 211 | /* PMC stuff */ |
209 | 212 | ||
@@ -232,6 +235,12 @@ static void register_cpu_online(unsigned int cpu) | |||
232 | 235 | ||
233 | if (cpu_has_feature(CPU_FTR_PURR)) | 236 | if (cpu_has_feature(CPU_FTR_PURR)) |
234 | sysdev_create_file(s, &attr_purr); | 237 | sysdev_create_file(s, &attr_purr); |
238 | |||
239 | if (cpu_has_feature(CPU_FTR_SPURR)) | ||
240 | sysdev_create_file(s, &attr_spurr); | ||
241 | |||
242 | if (cpu_has_feature(CPU_FTR_DSCR)) | ||
243 | sysdev_create_file(s, &attr_dscr); | ||
235 | } | 244 | } |
236 | 245 | ||
237 | #ifdef CONFIG_HOTPLUG_CPU | 246 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -240,12 +249,11 @@ static void unregister_cpu_online(unsigned int cpu) | |||
240 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 249 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
241 | struct sys_device *s = &c->sysdev; | 250 | struct sys_device *s = &c->sysdev; |
242 | 251 | ||
243 | BUG_ON(c->no_control); | 252 | BUG_ON(!c->hotpluggable); |
244 | 253 | ||
245 | #ifndef CONFIG_PPC_ISERIES | 254 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && |
246 | if (cpu_has_feature(CPU_FTR_SMT)) | 255 | cpu_has_feature(CPU_FTR_SMT)) |
247 | sysdev_remove_file(s, &attr_smt_snooze_delay); | 256 | sysdev_remove_file(s, &attr_smt_snooze_delay); |
248 | #endif | ||
249 | 257 | ||
250 | /* PMC stuff */ | 258 | /* PMC stuff */ |
251 | 259 | ||
@@ -274,6 +282,12 @@ static void unregister_cpu_online(unsigned int cpu) | |||
274 | 282 | ||
275 | if (cpu_has_feature(CPU_FTR_PURR)) | 283 | if (cpu_has_feature(CPU_FTR_PURR)) |
276 | sysdev_remove_file(s, &attr_purr); | 284 | sysdev_remove_file(s, &attr_purr); |
285 | |||
286 | if (cpu_has_feature(CPU_FTR_SPURR)) | ||
287 | sysdev_remove_file(s, &attr_spurr); | ||
288 | |||
289 | if (cpu_has_feature(CPU_FTR_DSCR)) | ||
290 | sysdev_remove_file(s, &attr_dscr); | ||
277 | } | 291 | } |
278 | #endif /* CONFIG_HOTPLUG_CPU */ | 292 | #endif /* CONFIG_HOTPLUG_CPU */ |
279 | 293 | ||
@@ -299,6 +313,72 @@ static struct notifier_block __cpuinitdata sysfs_cpu_nb = { | |||
299 | .notifier_call = sysfs_cpu_notify, | 313 | .notifier_call = sysfs_cpu_notify, |
300 | }; | 314 | }; |
301 | 315 | ||
316 | static DEFINE_MUTEX(cpu_mutex); | ||
317 | |||
318 | int cpu_add_sysdev_attr(struct sysdev_attribute *attr) | ||
319 | { | ||
320 | int cpu; | ||
321 | |||
322 | mutex_lock(&cpu_mutex); | ||
323 | |||
324 | for_each_possible_cpu(cpu) { | ||
325 | sysdev_create_file(get_cpu_sysdev(cpu), attr); | ||
326 | } | ||
327 | |||
328 | mutex_unlock(&cpu_mutex); | ||
329 | return 0; | ||
330 | } | ||
331 | EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr); | ||
332 | |||
333 | int cpu_add_sysdev_attr_group(struct attribute_group *attrs) | ||
334 | { | ||
335 | int cpu; | ||
336 | struct sys_device *sysdev; | ||
337 | |||
338 | mutex_lock(&cpu_mutex); | ||
339 | |||
340 | for_each_possible_cpu(cpu) { | ||
341 | sysdev = get_cpu_sysdev(cpu); | ||
342 | sysfs_create_group(&sysdev->kobj, attrs); | ||
343 | } | ||
344 | |||
345 | mutex_unlock(&cpu_mutex); | ||
346 | return 0; | ||
347 | } | ||
348 | EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group); | ||
349 | |||
350 | |||
351 | void cpu_remove_sysdev_attr(struct sysdev_attribute *attr) | ||
352 | { | ||
353 | int cpu; | ||
354 | |||
355 | mutex_lock(&cpu_mutex); | ||
356 | |||
357 | for_each_possible_cpu(cpu) { | ||
358 | sysdev_remove_file(get_cpu_sysdev(cpu), attr); | ||
359 | } | ||
360 | |||
361 | mutex_unlock(&cpu_mutex); | ||
362 | } | ||
363 | EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr); | ||
364 | |||
365 | void cpu_remove_sysdev_attr_group(struct attribute_group *attrs) | ||
366 | { | ||
367 | int cpu; | ||
368 | struct sys_device *sysdev; | ||
369 | |||
370 | mutex_lock(&cpu_mutex); | ||
371 | |||
372 | for_each_possible_cpu(cpu) { | ||
373 | sysdev = get_cpu_sysdev(cpu); | ||
374 | sysfs_remove_group(&sysdev->kobj, attrs); | ||
375 | } | ||
376 | |||
377 | mutex_unlock(&cpu_mutex); | ||
378 | } | ||
379 | EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group); | ||
380 | |||
381 | |||
302 | /* NUMA stuff */ | 382 | /* NUMA stuff */ |
303 | 383 | ||
304 | #ifdef CONFIG_NUMA | 384 | #ifdef CONFIG_NUMA |
@@ -360,10 +440,10 @@ static int __init topology_init(void) | |||
360 | * CPU. For instance, the boot cpu might never be valid | 440 | * CPU. For instance, the boot cpu might never be valid |
361 | * for hotplugging. | 441 | * for hotplugging. |
362 | */ | 442 | */ |
363 | if (!ppc_md.cpu_die) | 443 | if (ppc_md.cpu_die) |
364 | c->no_control = 1; | 444 | c->hotpluggable = 1; |
365 | 445 | ||
366 | if (cpu_online(cpu) || (c->no_control == 0)) { | 446 | if (cpu_online(cpu) || c->hotpluggable) { |
367 | register_cpu(c, cpu); | 447 | register_cpu(c, cpu); |
368 | 448 | ||
369 | sysdev_create_file(&c->sysdev, &attr_physical_id); | 449 | sysdev_create_file(&c->sysdev, &attr_physical_id); |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 5b59bc18dfe7..f6f0c6b07c4c 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 */ |
@@ -662,7 +631,8 @@ void timer_interrupt(struct pt_regs * regs) | |||
662 | calculate_steal_time(); | 631 | calculate_steal_time(); |
663 | 632 | ||
664 | #ifdef CONFIG_PPC_ISERIES | 633 | #ifdef CONFIG_PPC_ISERIES |
665 | get_lppaca()->int_dword.fields.decr_int = 0; | 634 | if (firmware_has_feature(FW_FEATURE_ISERIES)) |
635 | get_lppaca()->int_dword.fields.decr_int = 0; | ||
666 | #endif | 636 | #endif |
667 | 637 | ||
668 | while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu))) | 638 | while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu))) |
@@ -705,7 +675,7 @@ void timer_interrupt(struct pt_regs * regs) | |||
705 | set_dec(next_dec); | 675 | set_dec(next_dec); |
706 | 676 | ||
707 | #ifdef CONFIG_PPC_ISERIES | 677 | #ifdef CONFIG_PPC_ISERIES |
708 | if (hvlpevent_is_pending()) | 678 | if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) |
709 | process_hvlpevents(); | 679 | process_hvlpevents(); |
710 | #endif | 680 | #endif |
711 | 681 | ||
@@ -805,7 +775,7 @@ int do_settimeofday(struct timespec *tv) | |||
805 | * settimeofday to perform this operation. | 775 | * settimeofday to perform this operation. |
806 | */ | 776 | */ |
807 | #ifdef CONFIG_PPC_ISERIES | 777 | #ifdef CONFIG_PPC_ISERIES |
808 | if (first_settimeofday) { | 778 | if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) { |
809 | iSeries_tb_recal(); | 779 | iSeries_tb_recal(); |
810 | first_settimeofday = 0; | 780 | first_settimeofday = 0; |
811 | } | 781 | } |
@@ -1045,48 +1015,6 @@ void __init time_init(void) | |||
1045 | set_dec(tb_ticks_per_jiffy); | 1015 | set_dec(tb_ticks_per_jiffy); |
1046 | } | 1016 | } |
1047 | 1017 | ||
1048 | #ifdef CONFIG_RTC_CLASS | ||
1049 | static int set_rtc_class_time(struct rtc_time *tm) | ||
1050 | { | ||
1051 | int err; | ||
1052 | struct class_device *class_dev = | ||
1053 | rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); | ||
1054 | |||
1055 | if (class_dev == NULL) | ||
1056 | return -ENODEV; | ||
1057 | |||
1058 | err = rtc_set_time(class_dev, tm); | ||
1059 | |||
1060 | rtc_class_close(class_dev); | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static void get_rtc_class_time(struct rtc_time *tm) | ||
1066 | { | ||
1067 | int err; | ||
1068 | struct class_device *class_dev = | ||
1069 | rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); | ||
1070 | |||
1071 | if (class_dev == NULL) | ||
1072 | return; | ||
1073 | |||
1074 | err = rtc_read_time(class_dev, tm); | ||
1075 | |||
1076 | rtc_class_close(class_dev); | ||
1077 | |||
1078 | return; | ||
1079 | } | ||
1080 | |||
1081 | int __init rtc_class_hookup(void) | ||
1082 | { | ||
1083 | ppc_md.get_rtc_time = get_rtc_class_time; | ||
1084 | ppc_md.set_rtc_time = set_rtc_class_time; | ||
1085 | |||
1086 | return 0; | ||
1087 | } | ||
1088 | #endif /* CONFIG_RTC_CLASS */ | ||
1089 | |||
1090 | 1018 | ||
1091 | #define FEBRUARY 2 | 1019 | #define FEBRUARY 2 |
1092 | #define STARTOFTIME 1970 | 1020 | #define STARTOFTIME 1970 |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index d9f10f2fc372..535f50665647 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/kprobes.h> | 32 | #include <linux/kprobes.h> |
33 | #include <linux/kexec.h> | 33 | #include <linux/kexec.h> |
34 | #include <linux/backlight.h> | 34 | #include <linux/backlight.h> |
35 | #include <linux/bug.h> | ||
35 | 36 | ||
36 | #include <asm/kdebug.h> | 37 | #include <asm/kdebug.h> |
37 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
@@ -53,10 +54,6 @@ | |||
53 | #endif | 54 | #endif |
54 | #include <asm/kexec.h> | 55 | #include <asm/kexec.h> |
55 | 56 | ||
56 | #ifdef CONFIG_PPC64 /* XXX */ | ||
57 | #define _IO_BASE pci_io_base | ||
58 | #endif | ||
59 | |||
60 | #ifdef CONFIG_DEBUGGER | 57 | #ifdef CONFIG_DEBUGGER |
61 | int (*__debugger)(struct pt_regs *regs); | 58 | int (*__debugger)(struct pt_regs *regs); |
62 | int (*__debugger_ipi)(struct pt_regs *regs); | 59 | int (*__debugger_ipi)(struct pt_regs *regs); |
@@ -241,7 +238,7 @@ void system_reset_exception(struct pt_regs *regs) | |||
241 | */ | 238 | */ |
242 | static inline int check_io_access(struct pt_regs *regs) | 239 | static inline int check_io_access(struct pt_regs *regs) |
243 | { | 240 | { |
244 | #if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) | 241 | #ifdef CONFIG_PPC32 |
245 | unsigned long msr = regs->msr; | 242 | unsigned long msr = regs->msr; |
246 | const struct exception_table_entry *entry; | 243 | const struct exception_table_entry *entry; |
247 | unsigned int *nip = (unsigned int *)regs->nip; | 244 | unsigned int *nip = (unsigned int *)regs->nip; |
@@ -274,7 +271,7 @@ static inline int check_io_access(struct pt_regs *regs) | |||
274 | return 1; | 271 | return 1; |
275 | } | 272 | } |
276 | } | 273 | } |
277 | #endif /* CONFIG_PPC_PMAC && CONFIG_PPC32 */ | 274 | #endif /* CONFIG_PPC32 */ |
278 | return 0; | 275 | return 0; |
279 | } | 276 | } |
280 | 277 | ||
@@ -731,54 +728,9 @@ static int emulate_instruction(struct pt_regs *regs) | |||
731 | return -EINVAL; | 728 | return -EINVAL; |
732 | } | 729 | } |
733 | 730 | ||
734 | /* | 731 | int is_valid_bugaddr(unsigned long addr) |
735 | * Look through the list of trap instructions that are used for BUG(), | ||
736 | * BUG_ON() and WARN_ON() and see if we hit one. At this point we know | ||
737 | * that the exception was caused by a trap instruction of some kind. | ||
738 | * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 | ||
739 | * otherwise. | ||
740 | */ | ||
741 | extern struct bug_entry __start___bug_table[], __stop___bug_table[]; | ||
742 | |||
743 | #ifndef CONFIG_MODULES | ||
744 | #define module_find_bug(x) NULL | ||
745 | #endif | ||
746 | |||
747 | struct bug_entry *find_bug(unsigned long bugaddr) | ||
748 | { | ||
749 | struct bug_entry *bug; | ||
750 | |||
751 | for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) | ||
752 | if (bugaddr == bug->bug_addr) | ||
753 | return bug; | ||
754 | return module_find_bug(bugaddr); | ||
755 | } | ||
756 | |||
757 | static int check_bug_trap(struct pt_regs *regs) | ||
758 | { | 732 | { |
759 | struct bug_entry *bug; | 733 | return is_kernel_addr(addr); |
760 | unsigned long addr; | ||
761 | |||
762 | if (regs->msr & MSR_PR) | ||
763 | return 0; /* not in kernel */ | ||
764 | addr = regs->nip; /* address of trap instruction */ | ||
765 | if (addr < PAGE_OFFSET) | ||
766 | return 0; | ||
767 | bug = find_bug(regs->nip); | ||
768 | if (bug == NULL) | ||
769 | return 0; | ||
770 | if (bug->line & BUG_WARNING_TRAP) { | ||
771 | /* this is a WARN_ON rather than BUG/BUG_ON */ | ||
772 | printk(KERN_ERR "Badness in %s at %s:%ld\n", | ||
773 | bug->function, bug->file, | ||
774 | bug->line & ~BUG_WARNING_TRAP); | ||
775 | dump_stack(); | ||
776 | return 1; | ||
777 | } | ||
778 | printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", | ||
779 | bug->function, bug->file, bug->line); | ||
780 | |||
781 | return 0; | ||
782 | } | 734 | } |
783 | 735 | ||
784 | void __kprobes program_check_exception(struct pt_regs *regs) | 736 | void __kprobes program_check_exception(struct pt_regs *regs) |
@@ -786,6 +738,8 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
786 | unsigned int reason = get_reason(regs); | 738 | unsigned int reason = get_reason(regs); |
787 | extern int do_mathemu(struct pt_regs *regs); | 739 | extern int do_mathemu(struct pt_regs *regs); |
788 | 740 | ||
741 | /* We can now get here via a FP Unavailable exception if the core | ||
742 | * has no FPU, in that case no reason flags will be set */ | ||
789 | #ifdef CONFIG_MATH_EMULATION | 743 | #ifdef CONFIG_MATH_EMULATION |
790 | /* (reason & REASON_ILLEGAL) would be the obvious thing here, | 744 | /* (reason & REASON_ILLEGAL) would be the obvious thing here, |
791 | * but there seems to be a hardware bug on the 405GP (RevD) | 745 | * but there seems to be a hardware bug on the 405GP (RevD) |
@@ -812,7 +766,9 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
812 | return; | 766 | return; |
813 | if (debugger_bpt(regs)) | 767 | if (debugger_bpt(regs)) |
814 | return; | 768 | return; |
815 | if (check_bug_trap(regs)) { | 769 | |
770 | if (!(regs->msr & MSR_PR) && /* not user-mode */ | ||
771 | report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) { | ||
816 | regs->nip += 4; | 772 | regs->nip += 4; |
817 | return; | 773 | return; |
818 | } | 774 | } |
@@ -843,7 +799,7 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
843 | 799 | ||
844 | void alignment_exception(struct pt_regs *regs) | 800 | void alignment_exception(struct pt_regs *regs) |
845 | { | 801 | { |
846 | int fixed = 0; | 802 | int sig, code, fixed = 0; |
847 | 803 | ||
848 | /* we don't implement logging of alignment exceptions */ | 804 | /* we don't implement logging of alignment exceptions */ |
849 | if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) | 805 | if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) |
@@ -857,14 +813,16 @@ void alignment_exception(struct pt_regs *regs) | |||
857 | 813 | ||
858 | /* Operand address was bad */ | 814 | /* Operand address was bad */ |
859 | if (fixed == -EFAULT) { | 815 | if (fixed == -EFAULT) { |
860 | if (user_mode(regs)) | 816 | sig = SIGSEGV; |
861 | _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); | 817 | code = SEGV_ACCERR; |
862 | else | 818 | } else { |
863 | /* Search exception table */ | 819 | sig = SIGBUS; |
864 | bad_page_fault(regs, regs->dar, SIGSEGV); | 820 | code = BUS_ADRALN; |
865 | return; | ||
866 | } | 821 | } |
867 | _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); | 822 | if (user_mode(regs)) |
823 | _exception(sig, regs, code, regs->dar); | ||
824 | else | ||
825 | bad_page_fault(regs, regs->dar, sig); | ||
868 | } | 826 | } |
869 | 827 | ||
870 | void StackOverflow(struct pt_regs *regs) | 828 | void StackOverflow(struct pt_regs *regs) |
@@ -900,14 +858,13 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs) | |||
900 | 858 | ||
901 | void altivec_unavailable_exception(struct pt_regs *regs) | 859 | void altivec_unavailable_exception(struct pt_regs *regs) |
902 | { | 860 | { |
903 | #if !defined(CONFIG_ALTIVEC) | ||
904 | if (user_mode(regs)) { | 861 | if (user_mode(regs)) { |
905 | /* A user program has executed an altivec instruction, | 862 | /* A user program has executed an altivec instruction, |
906 | but this kernel doesn't support altivec. */ | 863 | but this kernel doesn't support altivec. */ |
907 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | 864 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); |
908 | return; | 865 | return; |
909 | } | 866 | } |
910 | #endif | 867 | |
911 | printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " | 868 | printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception " |
912 | "%lx at %lx\n", regs->trap, regs->nip); | 869 | "%lx at %lx\n", regs->trap, regs->nip); |
913 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); | 870 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); |
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 1a7e19cdab39..a4b28c73bba0 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 |
@@ -262,7 +264,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, | |||
262 | 264 | ||
263 | 265 | ||
264 | /* Allocate a VMA structure and fill it up */ | 266 | /* Allocate a VMA structure and fill it up */ |
265 | vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); | 267 | vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); |
266 | if (vma == NULL) { | 268 | if (vma == NULL) { |
267 | rc = -ENOMEM; | 269 | rc = -ENOMEM; |
268 | goto fail_mmapsem; | 270 | goto fail_mmapsem; |
@@ -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..a80f8f1d2e5d 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
@@ -81,20 +81,20 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | |||
81 | struct iommu_table *tbl; | 81 | struct iommu_table *tbl; |
82 | unsigned long offset, size; | 82 | unsigned long offset, size; |
83 | 83 | ||
84 | dma_window = get_property(dev->dev.platform_data, | 84 | dma_window = get_property(dev->dev.archdata.of_node, |
85 | "ibm,my-dma-window", NULL); | 85 | "ibm,my-dma-window", NULL); |
86 | if (!dma_window) | 86 | if (!dma_window) |
87 | return NULL; | 87 | return NULL; |
88 | 88 | ||
89 | tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); | 89 | tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); |
90 | 90 | ||
91 | of_parse_dma_window(dev->dev.platform_data, dma_window, | 91 | of_parse_dma_window(dev->dev.archdata.of_node, dma_window, |
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 | ||
@@ -117,7 +117,8 @@ static const struct vio_device_id *vio_match_device( | |||
117 | { | 117 | { |
118 | while (ids->type[0] != '\0') { | 118 | while (ids->type[0] != '\0') { |
119 | if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && | 119 | if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && |
120 | device_is_compatible(dev->dev.platform_data, ids->compat)) | 120 | device_is_compatible(dev->dev.archdata.of_node, |
121 | ids->compat)) | ||
121 | return ids; | 122 | return ids; |
122 | ids++; | 123 | ids++; |
123 | } | 124 | } |
@@ -198,9 +199,9 @@ EXPORT_SYMBOL(vio_unregister_driver); | |||
198 | /* vio_dev refcount hit 0 */ | 199 | /* vio_dev refcount hit 0 */ |
199 | static void __devinit vio_dev_release(struct device *dev) | 200 | static void __devinit vio_dev_release(struct device *dev) |
200 | { | 201 | { |
201 | if (dev->platform_data) { | 202 | if (dev->archdata.of_node) { |
202 | /* XXX free TCE table */ | 203 | /* XXX should free TCE table */ |
203 | of_node_put(dev->platform_data); | 204 | of_node_put(dev->archdata.of_node); |
204 | } | 205 | } |
205 | kfree(to_vio_dev(dev)); | 206 | kfree(to_vio_dev(dev)); |
206 | } | 207 | } |
@@ -210,7 +211,7 @@ static void __devinit vio_dev_release(struct device *dev) | |||
210 | * @of_node: The OF node for this device. | 211 | * @of_node: The OF node for this device. |
211 | * | 212 | * |
212 | * Creates and initializes a vio_dev structure from the data in | 213 | * Creates and initializes a vio_dev structure from the data in |
213 | * of_node (dev.platform_data) and adds it to the list of virtual devices. | 214 | * of_node and adds it to the list of virtual devices. |
214 | * Returns a pointer to the created vio_dev or NULL if node has | 215 | * Returns a pointer to the created vio_dev or NULL if node has |
215 | * NULL device_type or compatible fields. | 216 | * NULL device_type or compatible fields. |
216 | */ | 217 | */ |
@@ -240,8 +241,6 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | |||
240 | if (viodev == NULL) | 241 | if (viodev == NULL) |
241 | return NULL; | 242 | return NULL; |
242 | 243 | ||
243 | viodev->dev.platform_data = of_node_get(of_node); | ||
244 | |||
245 | viodev->irq = irq_of_parse_and_map(of_node, 0); | 244 | viodev->irq = irq_of_parse_and_map(of_node, 0); |
246 | 245 | ||
247 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); | 246 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); |
@@ -254,7 +253,10 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | |||
254 | if (unit_address != NULL) | 253 | if (unit_address != NULL) |
255 | viodev->unit_address = *unit_address; | 254 | viodev->unit_address = *unit_address; |
256 | } | 255 | } |
257 | viodev->iommu_table = vio_build_iommu_table(viodev); | 256 | viodev->dev.archdata.of_node = of_node_get(of_node); |
257 | viodev->dev.archdata.dma_ops = &dma_iommu_ops; | ||
258 | viodev->dev.archdata.dma_data = vio_build_iommu_table(viodev); | ||
259 | viodev->dev.archdata.numa_node = of_node_to_nid(of_node); | ||
258 | 260 | ||
259 | /* init generic 'struct device' fields: */ | 261 | /* init generic 'struct device' fields: */ |
260 | viodev->dev.parent = &vio_bus_device.dev; | 262 | viodev->dev.parent = &vio_bus_device.dev; |
@@ -285,10 +287,11 @@ static int __init vio_bus_init(void) | |||
285 | #ifdef CONFIG_PPC_ISERIES | 287 | #ifdef CONFIG_PPC_ISERIES |
286 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | 288 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { |
287 | iommu_vio_init(); | 289 | iommu_vio_init(); |
288 | vio_bus_device.iommu_table = &vio_iommu_table; | 290 | vio_bus_device.dev.archdata.dma_ops = &dma_iommu_ops; |
291 | vio_bus_device.dev.archdata.dma_data = &vio_iommu_table; | ||
289 | iSeries_vio_dev = &vio_bus_device.dev; | 292 | iSeries_vio_dev = &vio_bus_device.dev; |
290 | } | 293 | } |
291 | #endif | 294 | #endif /* CONFIG_PPC_ISERIES */ |
292 | 295 | ||
293 | err = bus_register(&vio_bus_type); | 296 | err = bus_register(&vio_bus_type); |
294 | if (err) { | 297 | if (err) { |
@@ -336,7 +339,7 @@ static ssize_t name_show(struct device *dev, | |||
336 | static ssize_t devspec_show(struct device *dev, | 339 | static ssize_t devspec_show(struct device *dev, |
337 | struct device_attribute *attr, char *buf) | 340 | struct device_attribute *attr, char *buf) |
338 | { | 341 | { |
339 | struct device_node *of_node = dev->platform_data; | 342 | struct device_node *of_node = dev->archdata.of_node; |
340 | 343 | ||
341 | return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); | 344 | return sprintf(buf, "%s\n", of_node ? of_node->full_name : "none"); |
342 | } | 345 | } |
@@ -353,62 +356,6 @@ void __devinit vio_unregister_device(struct vio_dev *viodev) | |||
353 | } | 356 | } |
354 | EXPORT_SYMBOL(vio_unregister_device); | 357 | EXPORT_SYMBOL(vio_unregister_device); |
355 | 358 | ||
356 | static dma_addr_t vio_map_single(struct device *dev, void *vaddr, | ||
357 | size_t size, enum dma_data_direction direction) | ||
358 | { | ||
359 | return iommu_map_single(to_vio_dev(dev)->iommu_table, vaddr, size, | ||
360 | ~0ul, direction); | ||
361 | } | ||
362 | |||
363 | static void vio_unmap_single(struct device *dev, dma_addr_t dma_handle, | ||
364 | size_t size, enum dma_data_direction direction) | ||
365 | { | ||
366 | iommu_unmap_single(to_vio_dev(dev)->iommu_table, dma_handle, size, | ||
367 | direction); | ||
368 | } | ||
369 | |||
370 | static int vio_map_sg(struct device *dev, struct scatterlist *sglist, | ||
371 | int nelems, enum dma_data_direction direction) | ||
372 | { | ||
373 | return iommu_map_sg(dev, to_vio_dev(dev)->iommu_table, sglist, | ||
374 | nelems, ~0ul, direction); | ||
375 | } | ||
376 | |||
377 | static void vio_unmap_sg(struct device *dev, struct scatterlist *sglist, | ||
378 | int nelems, enum dma_data_direction direction) | ||
379 | { | ||
380 | iommu_unmap_sg(to_vio_dev(dev)->iommu_table, sglist, nelems, direction); | ||
381 | } | ||
382 | |||
383 | static void *vio_alloc_coherent(struct device *dev, size_t size, | ||
384 | dma_addr_t *dma_handle, gfp_t flag) | ||
385 | { | ||
386 | return iommu_alloc_coherent(to_vio_dev(dev)->iommu_table, size, | ||
387 | dma_handle, ~0ul, flag, -1); | ||
388 | } | ||
389 | |||
390 | static void vio_free_coherent(struct device *dev, size_t size, | ||
391 | void *vaddr, dma_addr_t dma_handle) | ||
392 | { | ||
393 | iommu_free_coherent(to_vio_dev(dev)->iommu_table, size, vaddr, | ||
394 | dma_handle); | ||
395 | } | ||
396 | |||
397 | static int vio_dma_supported(struct device *dev, u64 mask) | ||
398 | { | ||
399 | return 1; | ||
400 | } | ||
401 | |||
402 | struct dma_mapping_ops vio_dma_ops = { | ||
403 | .alloc_coherent = vio_alloc_coherent, | ||
404 | .free_coherent = vio_free_coherent, | ||
405 | .map_single = vio_map_single, | ||
406 | .unmap_single = vio_unmap_single, | ||
407 | .map_sg = vio_map_sg, | ||
408 | .unmap_sg = vio_unmap_sg, | ||
409 | .dma_supported = vio_dma_supported, | ||
410 | }; | ||
411 | |||
412 | static int vio_bus_match(struct device *dev, struct device_driver *drv) | 359 | static int vio_bus_match(struct device *dev, struct device_driver *drv) |
413 | { | 360 | { |
414 | const struct vio_dev *vio_dev = to_vio_dev(dev); | 361 | const struct vio_dev *vio_dev = to_vio_dev(dev); |
@@ -422,13 +369,14 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, | |||
422 | char *buffer, int buffer_size) | 369 | char *buffer, int buffer_size) |
423 | { | 370 | { |
424 | const struct vio_dev *vio_dev = to_vio_dev(dev); | 371 | const struct vio_dev *vio_dev = to_vio_dev(dev); |
425 | struct device_node *dn = dev->platform_data; | 372 | struct device_node *dn; |
426 | const char *cp; | 373 | const char *cp; |
427 | int length; | 374 | int length; |
428 | 375 | ||
429 | if (!num_envp) | 376 | if (!num_envp) |
430 | return -ENOMEM; | 377 | return -ENOMEM; |
431 | 378 | ||
379 | dn = dev->archdata.of_node; | ||
432 | if (!dn) | 380 | if (!dn) |
433 | return -ENODEV; | 381 | return -ENODEV; |
434 | cp = get_property(dn, "compatible", &length); | 382 | cp = get_property(dn, "compatible", &length); |
@@ -465,7 +413,7 @@ struct bus_type vio_bus_type = { | |||
465 | */ | 413 | */ |
466 | const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) | 414 | const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length) |
467 | { | 415 | { |
468 | return get_property(vdev->dev.platform_data, which, length); | 416 | return get_property(vdev->dev.archdata.of_node, which, length); |
469 | } | 417 | } |
470 | EXPORT_SYMBOL(vio_get_attribute); | 418 | EXPORT_SYMBOL(vio_get_attribute); |
471 | 419 | ||
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index cb0e8d46c3e8..04b8e71bf5b0 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -33,6 +33,7 @@ SECTIONS | |||
33 | 33 | ||
34 | /* Text and gots */ | 34 | /* Text and gots */ |
35 | .text : { | 35 | .text : { |
36 | _text = .; | ||
36 | *(.text .text.*) | 37 | *(.text .text.*) |
37 | SCHED_TEXT | 38 | SCHED_TEXT |
38 | LOCK_TEXT | 39 | LOCK_TEXT |
@@ -61,11 +62,7 @@ SECTIONS | |||
61 | __stop___ex_table = .; | 62 | __stop___ex_table = .; |
62 | } | 63 | } |
63 | 64 | ||
64 | __bug_table : { | 65 | BUG_TABLE |
65 | __start___bug_table = .; | ||
66 | *(__bug_table) | ||
67 | __stop___bug_table = .; | ||
68 | } | ||
69 | 66 | ||
70 | /* | 67 | /* |
71 | * Init sections discarded at runtime | 68 | * Init sections discarded at runtime |
@@ -108,13 +105,7 @@ SECTIONS | |||
108 | 105 | ||
109 | .initcall.init : { | 106 | .initcall.init : { |
110 | __initcall_start = .; | 107 | __initcall_start = .; |
111 | *(.initcall1.init) | 108 | INITCALLS |
112 | *(.initcall2.init) | ||
113 | *(.initcall3.init) | ||
114 | *(.initcall4.init) | ||
115 | *(.initcall5.init) | ||
116 | *(.initcall6.init) | ||
117 | *(.initcall7.init) | ||
118 | __initcall_end = .; | 109 | __initcall_end = .; |
119 | } | 110 | } |
120 | 111 | ||