diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-09 13:03:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-09 13:03:44 -0500 |
commit | 6150c32589d1976ca8a5c987df951088c05a7542 (patch) | |
tree | 94073696576323ff966e365d8c47b8ecd8372f97 /arch/powerpc/kernel | |
parent | 44637a12f80b80157d9c1bc5b7d6ef09c9e05713 (diff) | |
parent | be42d5fa3772241b8ecebd443f1fb36247959c54 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge
Diffstat (limited to 'arch/powerpc/kernel')
41 files changed, 3104 insertions, 1494 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 9ed551b6c172..6e03b595b6c8 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 systbl.o \ | 18 | signal_64.o ptrace32.o systbl.o \ |
19 | paca.o ioctl32.o cpu_setup_power4.o \ | 19 | paca.o ioctl32.o cpu_setup_power4.o \ |
20 | firmware.o sysfs.o udbg.o idle_64.o | 20 | firmware.o sysfs.o idle_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_POWER4) += idle_power4.o | 23 | obj-$(CONFIG_POWER4) += idle_power4.o |
24 | obj-$(CONFIG_PPC_OF) += of_device.o | 24 | obj-$(CONFIG_PPC_OF) += of_device.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 |
@@ -30,12 +30,10 @@ obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o | |||
30 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o | 30 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o |
31 | obj-$(CONFIG_LPARCFG) += lparcfg.o | 31 | 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_GENERIC_TBSYNC) += smp-tbsync.o | 34 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
34 | obj-$(CONFIG_PPC_PSERIES) += udbg_16550.o | ||
35 | obj-$(CONFIG_PPC_MAPLE) += udbg_16550.o | ||
36 | udbgscc-$(CONFIG_PPC64) := udbg_scc.o | ||
37 | obj-$(CONFIG_PPC_PMAC) += $(udbgscc-y) | ||
38 | obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o | 35 | obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o |
36 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | ||
39 | 37 | ||
40 | ifeq ($(CONFIG_PPC_MERGE),y) | 38 | ifeq ($(CONFIG_PPC_MERGE),y) |
41 | 39 | ||
@@ -48,25 +46,25 @@ extra-$(CONFIG_8xx) := head_8xx.o | |||
48 | extra-y += vmlinux.lds | 46 | extra-y += vmlinux.lds |
49 | 47 | ||
50 | obj-y += process.o init_task.o time.o \ | 48 | obj-y += process.o init_task.o time.o \ |
51 | prom.o traps.o setup-common.o | 49 | prom.o traps.o setup-common.o udbg.o |
52 | obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o | 50 | obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o |
53 | obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o | 51 | obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o |
54 | obj-$(CONFIG_PPC_OF) += prom_init.o | 52 | obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o |
55 | obj-$(CONFIG_MODULES) += ppc_ksyms.o | 53 | obj-$(CONFIG_MODULES) += ppc_ksyms.o |
56 | obj-$(CONFIG_BOOTX_TEXT) += btext.o | 54 | obj-$(CONFIG_BOOTX_TEXT) += btext.o |
57 | obj-$(CONFIG_6xx) += idle_6xx.o | 55 | obj-$(CONFIG_6xx) += idle_6xx.o |
58 | obj-$(CONFIG_SMP) += smp.o | 56 | obj-$(CONFIG_SMP) += smp.o |
59 | obj-$(CONFIG_KPROBES) += kprobes.o | 57 | obj-$(CONFIG_KPROBES) += kprobes.o |
60 | 58 | obj-$(CONFIG_SERIAL_8250) += legacy_serial.o udbg_16550.o | |
61 | module-$(CONFIG_PPC64) += module_64.o | 59 | module-$(CONFIG_PPC64) += module_64.o |
62 | obj-$(CONFIG_MODULES) += $(module-y) | 60 | obj-$(CONFIG_MODULES) += $(module-y) |
63 | 61 | ||
64 | pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \ | 62 | pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \ |
65 | pci_direct_iommu.o iomap.o | 63 | pci_direct_iommu.o iomap.o |
66 | obj-$(CONFIG_PCI) += $(pci64-y) | 64 | obj-$(CONFIG_PCI) += $(pci64-y) |
67 | 65 | kexec-$(CONFIG_PPC64) := machine_kexec_64.o | |
68 | kexec64-$(CONFIG_PPC64) += machine_kexec_64.o | 66 | kexec-$(CONFIG_PPC32) := machine_kexec_32.o |
69 | obj-$(CONFIG_KEXEC) += $(kexec64-y) | 67 | obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y) |
70 | 68 | ||
71 | ifeq ($(CONFIG_PPC_ISERIES),y) | 69 | ifeq ($(CONFIG_PPC_ISERIES),y) |
72 | $(obj)/head_64.o: $(obj)/lparmap.s | 70 | $(obj)/head_64.o: $(obj)/lparmap.s |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 91538d2445bf..56399c5c931a 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -92,9 +92,9 @@ int main(void) | |||
92 | 92 | ||
93 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 93 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); |
94 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); | 94 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); |
95 | DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); | 95 | DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame)); |
96 | #ifdef CONFIG_PPC32 | ||
97 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | 96 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); |
97 | #ifdef CONFIG_PPC32 | ||
98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); | 98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); |
99 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | 99 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); |
100 | #endif /* CONFIG_PPC32 */ | 100 | #endif /* CONFIG_PPC32 */ |
@@ -131,11 +131,9 @@ int main(void) | |||
131 | DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); | 131 | DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); |
132 | DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); | 132 | DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); |
133 | #endif /* CONFIG_HUGETLB_PAGE */ | 133 | #endif /* CONFIG_HUGETLB_PAGE */ |
134 | DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); | ||
135 | DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); | 134 | DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); |
136 | DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); | 135 | DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc)); |
137 | DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); | 136 | DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb)); |
138 | DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi)); | ||
139 | DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); | 137 | DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp)); |
140 | DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); | 138 | DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca)); |
141 | DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); | 139 | DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id)); |
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index bdfba92b2b38..6223d39177cb 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c | |||
@@ -31,15 +31,18 @@ static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb); | |||
31 | static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); | 31 | static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb); |
32 | static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); | 32 | static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb); |
33 | 33 | ||
34 | static int g_loc_X; | 34 | #define __force_data __attribute__((__section__(".data"))) |
35 | static int g_loc_Y; | ||
36 | static int g_max_loc_X; | ||
37 | static int g_max_loc_Y; | ||
38 | 35 | ||
39 | static int dispDeviceRowBytes; | 36 | static int g_loc_X __force_data; |
40 | static int dispDeviceDepth; | 37 | static int g_loc_Y __force_data; |
41 | static int dispDeviceRect[4]; | 38 | static int g_max_loc_X __force_data; |
42 | static unsigned char *dispDeviceBase, *logicalDisplayBase; | 39 | static int g_max_loc_Y __force_data; |
40 | |||
41 | static int dispDeviceRowBytes __force_data; | ||
42 | static int dispDeviceDepth __force_data; | ||
43 | static int dispDeviceRect[4] __force_data; | ||
44 | static unsigned char *dispDeviceBase __force_data; | ||
45 | static unsigned char *logicalDisplayBase __force_data; | ||
43 | 46 | ||
44 | unsigned long disp_BAT[2] __initdata = {0, 0}; | 47 | unsigned long disp_BAT[2] __initdata = {0, 0}; |
45 | 48 | ||
@@ -47,7 +50,7 @@ unsigned long disp_BAT[2] __initdata = {0, 0}; | |||
47 | 50 | ||
48 | static unsigned char vga_font[cmapsz]; | 51 | static unsigned char vga_font[cmapsz]; |
49 | 52 | ||
50 | int boot_text_mapped; | 53 | int boot_text_mapped __force_data = 0; |
51 | int force_printk_to_btext = 0; | 54 | int force_printk_to_btext = 0; |
52 | 55 | ||
53 | #ifdef CONFIG_PPC32 | 56 | #ifdef CONFIG_PPC32 |
@@ -57,7 +60,7 @@ int force_printk_to_btext = 0; | |||
57 | * | 60 | * |
58 | * The display is mapped to virtual address 0xD0000000, rather | 61 | * The display is mapped to virtual address 0xD0000000, rather |
59 | * than 1:1, because some some CHRP machines put the frame buffer | 62 | * than 1:1, because some some CHRP machines put the frame buffer |
60 | * in the region starting at 0xC0000000 (KERNELBASE). | 63 | * in the region starting at 0xC0000000 (PAGE_OFFSET). |
61 | * This mapping is temporary and will disappear as soon as the | 64 | * This mapping is temporary and will disappear as soon as the |
62 | * setup done by MMU_Init() is applied. | 65 | * setup done by MMU_Init() is applied. |
63 | * | 66 | * |
@@ -66,10 +69,9 @@ int force_printk_to_btext = 0; | |||
66 | * is really badly aligned, but I didn't encounter this case | 69 | * is really badly aligned, but I didn't encounter this case |
67 | * yet. | 70 | * yet. |
68 | */ | 71 | */ |
69 | void __init | 72 | void __init btext_prepare_BAT(void) |
70 | btext_prepare_BAT(void) | ||
71 | { | 73 | { |
72 | unsigned long vaddr = KERNELBASE + 0x10000000; | 74 | unsigned long vaddr = PAGE_OFFSET + 0x10000000; |
73 | unsigned long addr; | 75 | unsigned long addr; |
74 | unsigned long lowbits; | 76 | unsigned long lowbits; |
75 | 77 | ||
@@ -95,12 +97,13 @@ btext_prepare_BAT(void) | |||
95 | } | 97 | } |
96 | #endif | 98 | #endif |
97 | 99 | ||
98 | /* This function will enable the early boot text when doing OF booting. This | 100 | |
99 | * way, xmon output should work too | 101 | /* This function can be used to enable the early boot text when doing |
102 | * OF booting or within bootx init. It must be followed by a btext_unmap() | ||
103 | * call before the logical address becomes unuseable | ||
100 | */ | 104 | */ |
101 | void __init | 105 | void __init btext_setup_display(int width, int height, int depth, int pitch, |
102 | btext_setup_display(int width, int height, int depth, int pitch, | 106 | unsigned long address) |
103 | unsigned long address) | ||
104 | { | 107 | { |
105 | g_loc_X = 0; | 108 | g_loc_X = 0; |
106 | g_loc_Y = 0; | 109 | g_loc_Y = 0; |
@@ -116,6 +119,11 @@ btext_setup_display(int width, int height, int depth, int pitch, | |||
116 | boot_text_mapped = 1; | 119 | boot_text_mapped = 1; |
117 | } | 120 | } |
118 | 121 | ||
122 | void __init btext_unmap(void) | ||
123 | { | ||
124 | boot_text_mapped = 0; | ||
125 | } | ||
126 | |||
119 | /* Here's a small text engine to use during early boot | 127 | /* Here's a small text engine to use during early boot |
120 | * or for debugging purposes | 128 | * or for debugging purposes |
121 | * | 129 | * |
@@ -127,7 +135,7 @@ btext_setup_display(int width, int height, int depth, int pitch, | |||
127 | * changes. | 135 | * changes. |
128 | */ | 136 | */ |
129 | 137 | ||
130 | void map_boot_text(void) | 138 | static void map_boot_text(void) |
131 | { | 139 | { |
132 | unsigned long base, offset, size; | 140 | unsigned long base, offset, size; |
133 | unsigned char *vbase; | 141 | unsigned char *vbase; |
@@ -175,8 +183,9 @@ int btext_initialize(struct device_node *np) | |||
175 | if (prop) | 183 | if (prop) |
176 | address = *prop; | 184 | address = *prop; |
177 | 185 | ||
178 | /* FIXME: Add support for PCI reg properties */ | 186 | /* FIXME: Add support for PCI reg properties. Right now, only |
179 | 187 | * reliable on macs | |
188 | */ | ||
180 | if (address == 0) | 189 | if (address == 0) |
181 | return -EINVAL; | 190 | return -EINVAL; |
182 | 191 | ||
@@ -184,7 +193,6 @@ int btext_initialize(struct device_node *np) | |||
184 | g_loc_Y = 0; | 193 | g_loc_Y = 0; |
185 | g_max_loc_X = width / 8; | 194 | g_max_loc_X = width / 8; |
186 | g_max_loc_Y = height / 16; | 195 | g_max_loc_Y = height / 16; |
187 | logicalDisplayBase = (unsigned char *)address; | ||
188 | dispDeviceBase = (unsigned char *)address; | 196 | dispDeviceBase = (unsigned char *)address; |
189 | dispDeviceRowBytes = pitch; | 197 | dispDeviceRowBytes = pitch; |
190 | dispDeviceDepth = depth; | 198 | dispDeviceDepth = depth; |
@@ -197,14 +205,12 @@ int btext_initialize(struct device_node *np) | |||
197 | return 0; | 205 | return 0; |
198 | } | 206 | } |
199 | 207 | ||
200 | void __init init_boot_display(void) | 208 | int __init btext_find_display(int allow_nonstdout) |
201 | { | 209 | { |
202 | char *name; | 210 | char *name; |
203 | struct device_node *np = NULL; | 211 | struct device_node *np = NULL; |
204 | int rc = -ENODEV; | 212 | int rc = -ENODEV; |
205 | 213 | ||
206 | printk("trying to initialize btext ...\n"); | ||
207 | |||
208 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | 214 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); |
209 | if (name != NULL) { | 215 | if (name != NULL) { |
210 | np = of_find_node_by_path(name); | 216 | np = of_find_node_by_path(name); |
@@ -218,8 +224,8 @@ void __init init_boot_display(void) | |||
218 | } | 224 | } |
219 | if (np) | 225 | if (np) |
220 | rc = btext_initialize(np); | 226 | rc = btext_initialize(np); |
221 | if (rc == 0) | 227 | if (rc == 0 || !allow_nonstdout) |
222 | return; | 228 | return rc; |
223 | 229 | ||
224 | for (np = NULL; (np = of_find_node_by_type(np, "display"));) { | 230 | for (np = NULL; (np = of_find_node_by_type(np, "display"));) { |
225 | if (get_property(np, "linux,opened", NULL)) { | 231 | if (get_property(np, "linux,opened", NULL)) { |
@@ -228,8 +234,9 @@ void __init init_boot_display(void) | |||
228 | printk("result: %d\n", rc); | 234 | printk("result: %d\n", rc); |
229 | } | 235 | } |
230 | if (rc == 0) | 236 | if (rc == 0) |
231 | return; | 237 | break; |
232 | } | 238 | } |
239 | return rc; | ||
233 | } | 240 | } |
234 | 241 | ||
235 | /* Calc the base address of a given point (x,y) */ | 242 | /* Calc the base address of a given point (x,y) */ |
@@ -277,44 +284,83 @@ EXPORT_SYMBOL(btext_update_display); | |||
277 | 284 | ||
278 | void btext_clearscreen(void) | 285 | void btext_clearscreen(void) |
279 | { | 286 | { |
280 | unsigned long *base = (unsigned long *)calc_base(0, 0); | 287 | unsigned int *base = (unsigned int *)calc_base(0, 0); |
281 | unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * | 288 | unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * |
282 | (dispDeviceDepth >> 3)) >> 3; | 289 | (dispDeviceDepth >> 3)) >> 2; |
283 | int i,j; | 290 | int i,j; |
284 | 291 | ||
285 | for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) | 292 | for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) |
286 | { | 293 | { |
287 | unsigned long *ptr = base; | 294 | unsigned int *ptr = base; |
288 | for(j=width; j; --j) | 295 | for(j=width; j; --j) |
289 | *(ptr++) = 0; | 296 | *(ptr++) = 0; |
290 | base += (dispDeviceRowBytes >> 3); | 297 | base += (dispDeviceRowBytes >> 2); |
291 | } | 298 | } |
292 | } | 299 | } |
293 | 300 | ||
301 | void btext_flushscreen(void) | ||
302 | { | ||
303 | unsigned int *base = (unsigned int *)calc_base(0, 0); | ||
304 | unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * | ||
305 | (dispDeviceDepth >> 3)) >> 2; | ||
306 | int i,j; | ||
307 | |||
308 | for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++) | ||
309 | { | ||
310 | unsigned int *ptr = base; | ||
311 | for(j = width; j > 0; j -= 8) { | ||
312 | __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr)); | ||
313 | ptr += 8; | ||
314 | } | ||
315 | base += (dispDeviceRowBytes >> 2); | ||
316 | } | ||
317 | __asm__ __volatile__ ("sync" ::: "memory"); | ||
318 | } | ||
319 | |||
320 | void btext_flushline(void) | ||
321 | { | ||
322 | unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4); | ||
323 | unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * | ||
324 | (dispDeviceDepth >> 3)) >> 2; | ||
325 | int i,j; | ||
326 | |||
327 | for (i=0; i < 16; i++) | ||
328 | { | ||
329 | unsigned int *ptr = base; | ||
330 | for(j = width; j > 0; j -= 8) { | ||
331 | __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr)); | ||
332 | ptr += 8; | ||
333 | } | ||
334 | base += (dispDeviceRowBytes >> 2); | ||
335 | } | ||
336 | __asm__ __volatile__ ("sync" ::: "memory"); | ||
337 | } | ||
338 | |||
339 | |||
294 | #ifndef NO_SCROLL | 340 | #ifndef NO_SCROLL |
295 | static void scrollscreen(void) | 341 | static void scrollscreen(void) |
296 | { | 342 | { |
297 | unsigned long *src = (unsigned long *)calc_base(0,16); | 343 | unsigned int *src = (unsigned int *)calc_base(0,16); |
298 | unsigned long *dst = (unsigned long *)calc_base(0,0); | 344 | unsigned int *dst = (unsigned int *)calc_base(0,0); |
299 | unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * | 345 | unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * |
300 | (dispDeviceDepth >> 3)) >> 3; | 346 | (dispDeviceDepth >> 3)) >> 2; |
301 | int i,j; | 347 | int i,j; |
302 | 348 | ||
303 | for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) | 349 | for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) |
304 | { | 350 | { |
305 | unsigned long *src_ptr = src; | 351 | unsigned int *src_ptr = src; |
306 | unsigned long *dst_ptr = dst; | 352 | unsigned int *dst_ptr = dst; |
307 | for(j=width; j; --j) | 353 | for(j=width; j; --j) |
308 | *(dst_ptr++) = *(src_ptr++); | 354 | *(dst_ptr++) = *(src_ptr++); |
309 | src += (dispDeviceRowBytes >> 3); | 355 | src += (dispDeviceRowBytes >> 2); |
310 | dst += (dispDeviceRowBytes >> 3); | 356 | dst += (dispDeviceRowBytes >> 2); |
311 | } | 357 | } |
312 | for (i=0; i<16; i++) | 358 | for (i=0; i<16; i++) |
313 | { | 359 | { |
314 | unsigned long *dst_ptr = dst; | 360 | unsigned int *dst_ptr = dst; |
315 | for(j=width; j; --j) | 361 | for(j=width; j; --j) |
316 | *(dst_ptr++) = 0; | 362 | *(dst_ptr++) = 0; |
317 | dst += (dispDeviceRowBytes >> 3); | 363 | dst += (dispDeviceRowBytes >> 2); |
318 | } | 364 | } |
319 | } | 365 | } |
320 | #endif /* ndef NO_SCROLL */ | 366 | #endif /* ndef NO_SCROLL */ |
@@ -377,6 +423,14 @@ void btext_drawstring(const char *c) | |||
377 | btext_drawchar(*c++); | 423 | btext_drawchar(*c++); |
378 | } | 424 | } |
379 | 425 | ||
426 | void btext_drawtext(const char *c, unsigned int len) | ||
427 | { | ||
428 | if (!boot_text_mapped) | ||
429 | return; | ||
430 | while (len--) | ||
431 | btext_drawchar(*c++); | ||
432 | } | ||
433 | |||
380 | void btext_drawhex(unsigned long v) | 434 | void btext_drawhex(unsigned long v) |
381 | { | 435 | { |
382 | char *hex_table = "0123456789abcdef"; | 436 | char *hex_table = "0123456789abcdef"; |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 1d85cedbbb7b..43c74a6b07b1 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -78,10 +78,8 @@ struct cpu_spec cpu_specs[] = { | |||
78 | .dcache_bsize = 128, | 78 | .dcache_bsize = 128, |
79 | .num_pmcs = 8, | 79 | .num_pmcs = 8, |
80 | .cpu_setup = __setup_cpu_power3, | 80 | .cpu_setup = __setup_cpu_power3, |
81 | #ifdef CONFIG_OPROFILE | ||
82 | .oprofile_cpu_type = "ppc64/power3", | 81 | .oprofile_cpu_type = "ppc64/power3", |
83 | .oprofile_model = &op_model_rs64, | 82 | .oprofile_type = RS64, |
84 | #endif | ||
85 | }, | 83 | }, |
86 | { /* Power3+ */ | 84 | { /* Power3+ */ |
87 | .pvr_mask = 0xffff0000, | 85 | .pvr_mask = 0xffff0000, |
@@ -93,10 +91,8 @@ struct cpu_spec cpu_specs[] = { | |||
93 | .dcache_bsize = 128, | 91 | .dcache_bsize = 128, |
94 | .num_pmcs = 8, | 92 | .num_pmcs = 8, |
95 | .cpu_setup = __setup_cpu_power3, | 93 | .cpu_setup = __setup_cpu_power3, |
96 | #ifdef CONFIG_OPROFILE | ||
97 | .oprofile_cpu_type = "ppc64/power3", | 94 | .oprofile_cpu_type = "ppc64/power3", |
98 | .oprofile_model = &op_model_rs64, | 95 | .oprofile_type = RS64, |
99 | #endif | ||
100 | }, | 96 | }, |
101 | { /* Northstar */ | 97 | { /* Northstar */ |
102 | .pvr_mask = 0xffff0000, | 98 | .pvr_mask = 0xffff0000, |
@@ -108,10 +104,8 @@ struct cpu_spec cpu_specs[] = { | |||
108 | .dcache_bsize = 128, | 104 | .dcache_bsize = 128, |
109 | .num_pmcs = 8, | 105 | .num_pmcs = 8, |
110 | .cpu_setup = __setup_cpu_power3, | 106 | .cpu_setup = __setup_cpu_power3, |
111 | #ifdef CONFIG_OPROFILE | ||
112 | .oprofile_cpu_type = "ppc64/rs64", | 107 | .oprofile_cpu_type = "ppc64/rs64", |
113 | .oprofile_model = &op_model_rs64, | 108 | .oprofile_type = RS64, |
114 | #endif | ||
115 | }, | 109 | }, |
116 | { /* Pulsar */ | 110 | { /* Pulsar */ |
117 | .pvr_mask = 0xffff0000, | 111 | .pvr_mask = 0xffff0000, |
@@ -123,10 +117,8 @@ struct cpu_spec cpu_specs[] = { | |||
123 | .dcache_bsize = 128, | 117 | .dcache_bsize = 128, |
124 | .num_pmcs = 8, | 118 | .num_pmcs = 8, |
125 | .cpu_setup = __setup_cpu_power3, | 119 | .cpu_setup = __setup_cpu_power3, |
126 | #ifdef CONFIG_OPROFILE | ||
127 | .oprofile_cpu_type = "ppc64/rs64", | 120 | .oprofile_cpu_type = "ppc64/rs64", |
128 | .oprofile_model = &op_model_rs64, | 121 | .oprofile_type = RS64, |
129 | #endif | ||
130 | }, | 122 | }, |
131 | { /* I-star */ | 123 | { /* I-star */ |
132 | .pvr_mask = 0xffff0000, | 124 | .pvr_mask = 0xffff0000, |
@@ -138,10 +130,8 @@ struct cpu_spec cpu_specs[] = { | |||
138 | .dcache_bsize = 128, | 130 | .dcache_bsize = 128, |
139 | .num_pmcs = 8, | 131 | .num_pmcs = 8, |
140 | .cpu_setup = __setup_cpu_power3, | 132 | .cpu_setup = __setup_cpu_power3, |
141 | #ifdef CONFIG_OPROFILE | ||
142 | .oprofile_cpu_type = "ppc64/rs64", | 133 | .oprofile_cpu_type = "ppc64/rs64", |
143 | .oprofile_model = &op_model_rs64, | 134 | .oprofile_type = RS64, |
144 | #endif | ||
145 | }, | 135 | }, |
146 | { /* S-star */ | 136 | { /* S-star */ |
147 | .pvr_mask = 0xffff0000, | 137 | .pvr_mask = 0xffff0000, |
@@ -153,10 +143,8 @@ struct cpu_spec cpu_specs[] = { | |||
153 | .dcache_bsize = 128, | 143 | .dcache_bsize = 128, |
154 | .num_pmcs = 8, | 144 | .num_pmcs = 8, |
155 | .cpu_setup = __setup_cpu_power3, | 145 | .cpu_setup = __setup_cpu_power3, |
156 | #ifdef CONFIG_OPROFILE | ||
157 | .oprofile_cpu_type = "ppc64/rs64", | 146 | .oprofile_cpu_type = "ppc64/rs64", |
158 | .oprofile_model = &op_model_rs64, | 147 | .oprofile_type = RS64, |
159 | #endif | ||
160 | }, | 148 | }, |
161 | { /* Power4 */ | 149 | { /* Power4 */ |
162 | .pvr_mask = 0xffff0000, | 150 | .pvr_mask = 0xffff0000, |
@@ -168,10 +156,8 @@ struct cpu_spec cpu_specs[] = { | |||
168 | .dcache_bsize = 128, | 156 | .dcache_bsize = 128, |
169 | .num_pmcs = 8, | 157 | .num_pmcs = 8, |
170 | .cpu_setup = __setup_cpu_power4, | 158 | .cpu_setup = __setup_cpu_power4, |
171 | #ifdef CONFIG_OPROFILE | ||
172 | .oprofile_cpu_type = "ppc64/power4", | 159 | .oprofile_cpu_type = "ppc64/power4", |
173 | .oprofile_model = &op_model_rs64, | 160 | .oprofile_type = POWER4, |
174 | #endif | ||
175 | }, | 161 | }, |
176 | { /* Power4+ */ | 162 | { /* Power4+ */ |
177 | .pvr_mask = 0xffff0000, | 163 | .pvr_mask = 0xffff0000, |
@@ -183,10 +169,8 @@ struct cpu_spec cpu_specs[] = { | |||
183 | .dcache_bsize = 128, | 169 | .dcache_bsize = 128, |
184 | .num_pmcs = 8, | 170 | .num_pmcs = 8, |
185 | .cpu_setup = __setup_cpu_power4, | 171 | .cpu_setup = __setup_cpu_power4, |
186 | #ifdef CONFIG_OPROFILE | ||
187 | .oprofile_cpu_type = "ppc64/power4", | 172 | .oprofile_cpu_type = "ppc64/power4", |
188 | .oprofile_model = &op_model_power4, | 173 | .oprofile_type = POWER4, |
189 | #endif | ||
190 | }, | 174 | }, |
191 | { /* PPC970 */ | 175 | { /* PPC970 */ |
192 | .pvr_mask = 0xffff0000, | 176 | .pvr_mask = 0xffff0000, |
@@ -199,10 +183,8 @@ struct cpu_spec cpu_specs[] = { | |||
199 | .dcache_bsize = 128, | 183 | .dcache_bsize = 128, |
200 | .num_pmcs = 8, | 184 | .num_pmcs = 8, |
201 | .cpu_setup = __setup_cpu_ppc970, | 185 | .cpu_setup = __setup_cpu_ppc970, |
202 | #ifdef CONFIG_OPROFILE | ||
203 | .oprofile_cpu_type = "ppc64/970", | 186 | .oprofile_cpu_type = "ppc64/970", |
204 | .oprofile_model = &op_model_power4, | 187 | .oprofile_type = POWER4, |
205 | #endif | ||
206 | }, | 188 | }, |
207 | #endif /* CONFIG_PPC64 */ | 189 | #endif /* CONFIG_PPC64 */ |
208 | #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4) | 190 | #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4) |
@@ -221,10 +203,8 @@ struct cpu_spec cpu_specs[] = { | |||
221 | .dcache_bsize = 128, | 203 | .dcache_bsize = 128, |
222 | .num_pmcs = 8, | 204 | .num_pmcs = 8, |
223 | .cpu_setup = __setup_cpu_ppc970, | 205 | .cpu_setup = __setup_cpu_ppc970, |
224 | #ifdef CONFIG_OPROFILE | ||
225 | .oprofile_cpu_type = "ppc64/970", | 206 | .oprofile_cpu_type = "ppc64/970", |
226 | .oprofile_model = &op_model_power4, | 207 | .oprofile_type = POWER4, |
227 | #endif | ||
228 | }, | 208 | }, |
229 | #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */ | 209 | #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */ |
230 | #ifdef CONFIG_PPC64 | 210 | #ifdef CONFIG_PPC64 |
@@ -238,10 +218,8 @@ struct cpu_spec cpu_specs[] = { | |||
238 | .icache_bsize = 128, | 218 | .icache_bsize = 128, |
239 | .dcache_bsize = 128, | 219 | .dcache_bsize = 128, |
240 | .cpu_setup = __setup_cpu_ppc970, | 220 | .cpu_setup = __setup_cpu_ppc970, |
241 | #ifdef CONFIG_OPROFILE | ||
242 | .oprofile_cpu_type = "ppc64/970", | 221 | .oprofile_cpu_type = "ppc64/970", |
243 | .oprofile_model = &op_model_power4, | 222 | .oprofile_type = POWER4, |
244 | #endif | ||
245 | }, | 223 | }, |
246 | { /* Power5 GR */ | 224 | { /* Power5 GR */ |
247 | .pvr_mask = 0xffff0000, | 225 | .pvr_mask = 0xffff0000, |
@@ -253,27 +231,23 @@ struct cpu_spec cpu_specs[] = { | |||
253 | .dcache_bsize = 128, | 231 | .dcache_bsize = 128, |
254 | .num_pmcs = 6, | 232 | .num_pmcs = 6, |
255 | .cpu_setup = __setup_cpu_power4, | 233 | .cpu_setup = __setup_cpu_power4, |
256 | #ifdef CONFIG_OPROFILE | ||
257 | .oprofile_cpu_type = "ppc64/power5", | 234 | .oprofile_cpu_type = "ppc64/power5", |
258 | .oprofile_model = &op_model_power4, | 235 | .oprofile_type = POWER4, |
259 | #endif | ||
260 | }, | 236 | }, |
261 | { /* Power5 GS */ | 237 | { /* Power5 GS */ |
262 | .pvr_mask = 0xffff0000, | 238 | .pvr_mask = 0xffff0000, |
263 | .pvr_value = 0x003b0000, | 239 | .pvr_value = 0x003b0000, |
264 | .cpu_name = "POWER5 (gs)", | 240 | .cpu_name = "POWER5+ (gs)", |
265 | .cpu_features = CPU_FTRS_POWER5, | 241 | .cpu_features = CPU_FTRS_POWER5, |
266 | .cpu_user_features = COMMON_USER_POWER5_PLUS, | 242 | .cpu_user_features = COMMON_USER_POWER5_PLUS, |
267 | .icache_bsize = 128, | 243 | .icache_bsize = 128, |
268 | .dcache_bsize = 128, | 244 | .dcache_bsize = 128, |
269 | .num_pmcs = 6, | 245 | .num_pmcs = 6, |
270 | .cpu_setup = __setup_cpu_power4, | 246 | .cpu_setup = __setup_cpu_power4, |
271 | #ifdef CONFIG_OPROFILE | 247 | .oprofile_cpu_type = "ppc64/power5+", |
272 | .oprofile_cpu_type = "ppc64/power5", | 248 | .oprofile_type = POWER4, |
273 | .oprofile_model = &op_model_power4, | ||
274 | #endif | ||
275 | }, | 249 | }, |
276 | { /* BE DD1.x */ | 250 | { /* Cell Broadband Engine */ |
277 | .pvr_mask = 0xffff0000, | 251 | .pvr_mask = 0xffff0000, |
278 | .pvr_value = 0x00700000, | 252 | .pvr_value = 0x00700000, |
279 | .cpu_name = "Cell Broadband Engine", | 253 | .cpu_name = "Cell Broadband Engine", |
@@ -545,7 +519,9 @@ struct cpu_spec cpu_specs[] = { | |||
545 | .icache_bsize = 32, | 519 | .icache_bsize = 32, |
546 | .dcache_bsize = 32, | 520 | .dcache_bsize = 32, |
547 | .num_pmcs = 6, | 521 | .num_pmcs = 6, |
548 | .cpu_setup = __setup_cpu_745x | 522 | .cpu_setup = __setup_cpu_745x, |
523 | .oprofile_cpu_type = "ppc/7450", | ||
524 | .oprofile_type = G4, | ||
549 | }, | 525 | }, |
550 | { /* 7450 2.1 */ | 526 | { /* 7450 2.1 */ |
551 | .pvr_mask = 0xffffffff, | 527 | .pvr_mask = 0xffffffff, |
@@ -556,7 +532,9 @@ struct cpu_spec cpu_specs[] = { | |||
556 | .icache_bsize = 32, | 532 | .icache_bsize = 32, |
557 | .dcache_bsize = 32, | 533 | .dcache_bsize = 32, |
558 | .num_pmcs = 6, | 534 | .num_pmcs = 6, |
559 | .cpu_setup = __setup_cpu_745x | 535 | .cpu_setup = __setup_cpu_745x, |
536 | .oprofile_cpu_type = "ppc/7450", | ||
537 | .oprofile_type = G4, | ||
560 | }, | 538 | }, |
561 | { /* 7450 2.3 and newer */ | 539 | { /* 7450 2.3 and newer */ |
562 | .pvr_mask = 0xffff0000, | 540 | .pvr_mask = 0xffff0000, |
@@ -567,7 +545,9 @@ struct cpu_spec cpu_specs[] = { | |||
567 | .icache_bsize = 32, | 545 | .icache_bsize = 32, |
568 | .dcache_bsize = 32, | 546 | .dcache_bsize = 32, |
569 | .num_pmcs = 6, | 547 | .num_pmcs = 6, |
570 | .cpu_setup = __setup_cpu_745x | 548 | .cpu_setup = __setup_cpu_745x, |
549 | .oprofile_cpu_type = "ppc/7450", | ||
550 | .oprofile_type = G4, | ||
571 | }, | 551 | }, |
572 | { /* 7455 rev 1.x */ | 552 | { /* 7455 rev 1.x */ |
573 | .pvr_mask = 0xffffff00, | 553 | .pvr_mask = 0xffffff00, |
@@ -578,7 +558,9 @@ struct cpu_spec cpu_specs[] = { | |||
578 | .icache_bsize = 32, | 558 | .icache_bsize = 32, |
579 | .dcache_bsize = 32, | 559 | .dcache_bsize = 32, |
580 | .num_pmcs = 6, | 560 | .num_pmcs = 6, |
581 | .cpu_setup = __setup_cpu_745x | 561 | .cpu_setup = __setup_cpu_745x, |
562 | .oprofile_cpu_type = "ppc/7450", | ||
563 | .oprofile_type = G4, | ||
582 | }, | 564 | }, |
583 | { /* 7455 rev 2.0 */ | 565 | { /* 7455 rev 2.0 */ |
584 | .pvr_mask = 0xffffffff, | 566 | .pvr_mask = 0xffffffff, |
@@ -589,7 +571,9 @@ struct cpu_spec cpu_specs[] = { | |||
589 | .icache_bsize = 32, | 571 | .icache_bsize = 32, |
590 | .dcache_bsize = 32, | 572 | .dcache_bsize = 32, |
591 | .num_pmcs = 6, | 573 | .num_pmcs = 6, |
592 | .cpu_setup = __setup_cpu_745x | 574 | .cpu_setup = __setup_cpu_745x, |
575 | .oprofile_cpu_type = "ppc/7450", | ||
576 | .oprofile_type = G4, | ||
593 | }, | 577 | }, |
594 | { /* 7455 others */ | 578 | { /* 7455 others */ |
595 | .pvr_mask = 0xffff0000, | 579 | .pvr_mask = 0xffff0000, |
@@ -600,7 +584,9 @@ struct cpu_spec cpu_specs[] = { | |||
600 | .icache_bsize = 32, | 584 | .icache_bsize = 32, |
601 | .dcache_bsize = 32, | 585 | .dcache_bsize = 32, |
602 | .num_pmcs = 6, | 586 | .num_pmcs = 6, |
603 | .cpu_setup = __setup_cpu_745x | 587 | .cpu_setup = __setup_cpu_745x, |
588 | .oprofile_cpu_type = "ppc/7450", | ||
589 | .oprofile_type = G4, | ||
604 | }, | 590 | }, |
605 | { /* 7447/7457 Rev 1.0 */ | 591 | { /* 7447/7457 Rev 1.0 */ |
606 | .pvr_mask = 0xffffffff, | 592 | .pvr_mask = 0xffffffff, |
@@ -611,7 +597,9 @@ struct cpu_spec cpu_specs[] = { | |||
611 | .icache_bsize = 32, | 597 | .icache_bsize = 32, |
612 | .dcache_bsize = 32, | 598 | .dcache_bsize = 32, |
613 | .num_pmcs = 6, | 599 | .num_pmcs = 6, |
614 | .cpu_setup = __setup_cpu_745x | 600 | .cpu_setup = __setup_cpu_745x, |
601 | .oprofile_cpu_type = "ppc/7450", | ||
602 | .oprofile_type = G4, | ||
615 | }, | 603 | }, |
616 | { /* 7447/7457 Rev 1.1 */ | 604 | { /* 7447/7457 Rev 1.1 */ |
617 | .pvr_mask = 0xffffffff, | 605 | .pvr_mask = 0xffffffff, |
@@ -622,7 +610,9 @@ struct cpu_spec cpu_specs[] = { | |||
622 | .icache_bsize = 32, | 610 | .icache_bsize = 32, |
623 | .dcache_bsize = 32, | 611 | .dcache_bsize = 32, |
624 | .num_pmcs = 6, | 612 | .num_pmcs = 6, |
625 | .cpu_setup = __setup_cpu_745x | 613 | .cpu_setup = __setup_cpu_745x, |
614 | .oprofile_cpu_type = "ppc/7450", | ||
615 | .oprofile_type = G4, | ||
626 | }, | 616 | }, |
627 | { /* 7447/7457 Rev 1.2 and later */ | 617 | { /* 7447/7457 Rev 1.2 and later */ |
628 | .pvr_mask = 0xffff0000, | 618 | .pvr_mask = 0xffff0000, |
@@ -633,7 +623,9 @@ struct cpu_spec cpu_specs[] = { | |||
633 | .icache_bsize = 32, | 623 | .icache_bsize = 32, |
634 | .dcache_bsize = 32, | 624 | .dcache_bsize = 32, |
635 | .num_pmcs = 6, | 625 | .num_pmcs = 6, |
636 | .cpu_setup = __setup_cpu_745x | 626 | .cpu_setup = __setup_cpu_745x, |
627 | .oprofile_cpu_type = "ppc/7450", | ||
628 | .oprofile_type = G4, | ||
637 | }, | 629 | }, |
638 | { /* 7447A */ | 630 | { /* 7447A */ |
639 | .pvr_mask = 0xffff0000, | 631 | .pvr_mask = 0xffff0000, |
@@ -644,7 +636,9 @@ struct cpu_spec cpu_specs[] = { | |||
644 | .icache_bsize = 32, | 636 | .icache_bsize = 32, |
645 | .dcache_bsize = 32, | 637 | .dcache_bsize = 32, |
646 | .num_pmcs = 6, | 638 | .num_pmcs = 6, |
647 | .cpu_setup = __setup_cpu_745x | 639 | .cpu_setup = __setup_cpu_745x, |
640 | .oprofile_cpu_type = "ppc/7450", | ||
641 | .oprofile_type = G4, | ||
648 | }, | 642 | }, |
649 | { /* 7448 */ | 643 | { /* 7448 */ |
650 | .pvr_mask = 0xffff0000, | 644 | .pvr_mask = 0xffff0000, |
@@ -655,7 +649,9 @@ struct cpu_spec cpu_specs[] = { | |||
655 | .icache_bsize = 32, | 649 | .icache_bsize = 32, |
656 | .dcache_bsize = 32, | 650 | .dcache_bsize = 32, |
657 | .num_pmcs = 6, | 651 | .num_pmcs = 6, |
658 | .cpu_setup = __setup_cpu_745x | 652 | .cpu_setup = __setup_cpu_745x, |
653 | .oprofile_cpu_type = "ppc/7450", | ||
654 | .oprofile_type = G4, | ||
659 | }, | 655 | }, |
660 | { /* 82xx (8240, 8245, 8260 are all 603e cores) */ | 656 | { /* 82xx (8240, 8245, 8260 are all 603e cores) */ |
661 | .pvr_mask = 0x7fff0000, | 657 | .pvr_mask = 0x7fff0000, |
@@ -979,6 +975,8 @@ struct cpu_spec cpu_specs[] = { | |||
979 | .icache_bsize = 32, | 975 | .icache_bsize = 32, |
980 | .dcache_bsize = 32, | 976 | .dcache_bsize = 32, |
981 | .num_pmcs = 4, | 977 | .num_pmcs = 4, |
978 | .oprofile_cpu_type = "ppc/e500", | ||
979 | .oprofile_type = BOOKE, | ||
982 | }, | 980 | }, |
983 | { /* e500v2 */ | 981 | { /* e500v2 */ |
984 | .pvr_mask = 0xffff0000, | 982 | .pvr_mask = 0xffff0000, |
@@ -992,6 +990,8 @@ struct cpu_spec cpu_specs[] = { | |||
992 | .icache_bsize = 32, | 990 | .icache_bsize = 32, |
993 | .dcache_bsize = 32, | 991 | .dcache_bsize = 32, |
994 | .num_pmcs = 4, | 992 | .num_pmcs = 4, |
993 | .oprofile_cpu_type = "ppc/e500", | ||
994 | .oprofile_type = BOOKE, | ||
995 | }, | 995 | }, |
996 | #endif | 996 | #endif |
997 | #if !CLASSIC_PPC | 997 | #if !CLASSIC_PPC |
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c new file mode 100644 index 000000000000..4681155121ef --- /dev/null +++ b/arch/powerpc/kernel/crash.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * Architecture specific (PPC64) functions for kexec based crash dumps. | ||
3 | * | ||
4 | * Copyright (C) 2005, IBM Corp. | ||
5 | * | ||
6 | * Created by: Haren Myneni | ||
7 | * | ||
8 | * This source code is licensed under the GNU General Public License, | ||
9 | * Version 2. See the file COPYING for more details. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #undef DEBUG | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/reboot.h> | ||
18 | #include <linux/kexec.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | #include <linux/crash_dump.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/elf.h> | ||
24 | #include <linux/elfcore.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/types.h> | ||
27 | |||
28 | #include <asm/processor.h> | ||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/kdump.h> | ||
31 | #include <asm/lmb.h> | ||
32 | #include <asm/firmware.h> | ||
33 | |||
34 | #ifdef DEBUG | ||
35 | #include <asm/udbg.h> | ||
36 | #define DBG(fmt...) udbg_printf(fmt) | ||
37 | #else | ||
38 | #define DBG(fmt...) | ||
39 | #endif | ||
40 | |||
41 | /* This keeps a track of which one is crashing cpu. */ | ||
42 | int crashing_cpu = -1; | ||
43 | |||
44 | static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, | ||
45 | size_t data_len) | ||
46 | { | ||
47 | struct elf_note note; | ||
48 | |||
49 | note.n_namesz = strlen(name) + 1; | ||
50 | note.n_descsz = data_len; | ||
51 | note.n_type = type; | ||
52 | memcpy(buf, ¬e, sizeof(note)); | ||
53 | buf += (sizeof(note) +3)/4; | ||
54 | memcpy(buf, name, note.n_namesz); | ||
55 | buf += (note.n_namesz + 3)/4; | ||
56 | memcpy(buf, data, note.n_descsz); | ||
57 | buf += (note.n_descsz + 3)/4; | ||
58 | |||
59 | return buf; | ||
60 | } | ||
61 | |||
62 | static void final_note(u32 *buf) | ||
63 | { | ||
64 | struct elf_note note; | ||
65 | |||
66 | note.n_namesz = 0; | ||
67 | note.n_descsz = 0; | ||
68 | note.n_type = 0; | ||
69 | memcpy(buf, ¬e, sizeof(note)); | ||
70 | } | ||
71 | |||
72 | static void crash_save_this_cpu(struct pt_regs *regs, int cpu) | ||
73 | { | ||
74 | struct elf_prstatus prstatus; | ||
75 | u32 *buf; | ||
76 | |||
77 | if ((cpu < 0) || (cpu >= NR_CPUS)) | ||
78 | return; | ||
79 | |||
80 | /* Using ELF notes here is opportunistic. | ||
81 | * I need a well defined structure format | ||
82 | * for the data I pass, and I need tags | ||
83 | * on the data to indicate what information I have | ||
84 | * squirrelled away. ELF notes happen to provide | ||
85 | * all of that that no need to invent something new. | ||
86 | */ | ||
87 | buf = &crash_notes[cpu][0]; | ||
88 | memset(&prstatus, 0, sizeof(prstatus)); | ||
89 | prstatus.pr_pid = current->pid; | ||
90 | elf_core_copy_regs(&prstatus.pr_reg, regs); | ||
91 | buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, | ||
92 | sizeof(prstatus)); | ||
93 | final_note(buf); | ||
94 | } | ||
95 | |||
96 | /* FIXME Merge this with xmon_save_regs ?? */ | ||
97 | static inline void crash_get_current_regs(struct pt_regs *regs) | ||
98 | { | ||
99 | unsigned long tmp1, tmp2; | ||
100 | |||
101 | __asm__ __volatile__ ( | ||
102 | "std 0,0(%2)\n" | ||
103 | "std 1,8(%2)\n" | ||
104 | "std 2,16(%2)\n" | ||
105 | "std 3,24(%2)\n" | ||
106 | "std 4,32(%2)\n" | ||
107 | "std 5,40(%2)\n" | ||
108 | "std 6,48(%2)\n" | ||
109 | "std 7,56(%2)\n" | ||
110 | "std 8,64(%2)\n" | ||
111 | "std 9,72(%2)\n" | ||
112 | "std 10,80(%2)\n" | ||
113 | "std 11,88(%2)\n" | ||
114 | "std 12,96(%2)\n" | ||
115 | "std 13,104(%2)\n" | ||
116 | "std 14,112(%2)\n" | ||
117 | "std 15,120(%2)\n" | ||
118 | "std 16,128(%2)\n" | ||
119 | "std 17,136(%2)\n" | ||
120 | "std 18,144(%2)\n" | ||
121 | "std 19,152(%2)\n" | ||
122 | "std 20,160(%2)\n" | ||
123 | "std 21,168(%2)\n" | ||
124 | "std 22,176(%2)\n" | ||
125 | "std 23,184(%2)\n" | ||
126 | "std 24,192(%2)\n" | ||
127 | "std 25,200(%2)\n" | ||
128 | "std 26,208(%2)\n" | ||
129 | "std 27,216(%2)\n" | ||
130 | "std 28,224(%2)\n" | ||
131 | "std 29,232(%2)\n" | ||
132 | "std 30,240(%2)\n" | ||
133 | "std 31,248(%2)\n" | ||
134 | "mfmsr %0\n" | ||
135 | "std %0, 264(%2)\n" | ||
136 | "mfctr %0\n" | ||
137 | "std %0, 280(%2)\n" | ||
138 | "mflr %0\n" | ||
139 | "std %0, 288(%2)\n" | ||
140 | "bl 1f\n" | ||
141 | "1: mflr %1\n" | ||
142 | "std %1, 256(%2)\n" | ||
143 | "mtlr %0\n" | ||
144 | "mfxer %0\n" | ||
145 | "std %0, 296(%2)\n" | ||
146 | : "=&r" (tmp1), "=&r" (tmp2) | ||
147 | : "b" (regs)); | ||
148 | } | ||
149 | |||
150 | /* We may have saved_regs from where the error came from | ||
151 | * or it is NULL if via a direct panic(). | ||
152 | */ | ||
153 | static void crash_save_self(struct pt_regs *saved_regs) | ||
154 | { | ||
155 | struct pt_regs regs; | ||
156 | int cpu; | ||
157 | |||
158 | cpu = smp_processor_id(); | ||
159 | if (saved_regs) | ||
160 | memcpy(®s, saved_regs, sizeof(regs)); | ||
161 | else | ||
162 | crash_get_current_regs(®s); | ||
163 | crash_save_this_cpu(®s, cpu); | ||
164 | } | ||
165 | |||
166 | #ifdef CONFIG_SMP | ||
167 | static atomic_t waiting_for_crash_ipi; | ||
168 | |||
169 | void crash_ipi_callback(struct pt_regs *regs) | ||
170 | { | ||
171 | int cpu = smp_processor_id(); | ||
172 | |||
173 | if (cpu == crashing_cpu) | ||
174 | return; | ||
175 | |||
176 | if (!cpu_online(cpu)) | ||
177 | return; | ||
178 | |||
179 | if (ppc_md.kexec_cpu_down) | ||
180 | ppc_md.kexec_cpu_down(1, 1); | ||
181 | |||
182 | local_irq_disable(); | ||
183 | |||
184 | crash_save_this_cpu(regs, cpu); | ||
185 | atomic_dec(&waiting_for_crash_ipi); | ||
186 | kexec_smp_wait(); | ||
187 | /* NOTREACHED */ | ||
188 | } | ||
189 | |||
190 | static void crash_kexec_prepare_cpus(void) | ||
191 | { | ||
192 | unsigned int msecs; | ||
193 | |||
194 | atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); | ||
195 | |||
196 | crash_send_ipi(crash_ipi_callback); | ||
197 | smp_wmb(); | ||
198 | |||
199 | /* | ||
200 | * FIXME: Until we will have the way to stop other CPUSs reliabally, | ||
201 | * the crash CPU will send an IPI and wait for other CPUs to | ||
202 | * respond. If not, proceed the kexec boot even though we failed to | ||
203 | * capture other CPU states. | ||
204 | */ | ||
205 | msecs = 1000000; | ||
206 | while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) { | ||
207 | barrier(); | ||
208 | mdelay(1); | ||
209 | } | ||
210 | |||
211 | /* Would it be better to replace the trap vector here? */ | ||
212 | |||
213 | /* | ||
214 | * FIXME: In case if we do not get all CPUs, one possibility: ask the | ||
215 | * user to do soft reset such that we get all. | ||
216 | * IPI handler is already set by the panic cpu initially. Therefore, | ||
217 | * all cpus could invoke this handler from die() and the panic CPU | ||
218 | * will call machine_kexec() directly from this handler to do | ||
219 | * kexec boot. | ||
220 | */ | ||
221 | if (atomic_read(&waiting_for_crash_ipi)) | ||
222 | printk(KERN_ALERT "done waiting: %d cpus not responding\n", | ||
223 | atomic_read(&waiting_for_crash_ipi)); | ||
224 | /* Leave the IPI callback set */ | ||
225 | } | ||
226 | #else | ||
227 | static void crash_kexec_prepare_cpus(void) | ||
228 | { | ||
229 | /* | ||
230 | * move the secondarys to us so that we can copy | ||
231 | * the new kernel 0-0x100 safely | ||
232 | * | ||
233 | * do this if kexec in setup.c ? | ||
234 | */ | ||
235 | smp_release_cpus(); | ||
236 | } | ||
237 | |||
238 | #endif | ||
239 | |||
240 | void default_machine_crash_shutdown(struct pt_regs *regs) | ||
241 | { | ||
242 | /* | ||
243 | * This function is only called after the system | ||
244 | * has paniced or is otherwise in a critical state. | ||
245 | * The minimum amount of code to allow a kexec'd kernel | ||
246 | * to run successfully needs to happen here. | ||
247 | * | ||
248 | * In practice this means stopping other cpus in | ||
249 | * an SMP system. | ||
250 | * The kernel is broken so disable interrupts. | ||
251 | */ | ||
252 | local_irq_disable(); | ||
253 | |||
254 | if (ppc_md.kexec_cpu_down) | ||
255 | ppc_md.kexec_cpu_down(1, 0); | ||
256 | |||
257 | /* | ||
258 | * Make a note of crashing cpu. Will be used in machine_kexec | ||
259 | * such that another IPI will not be sent. | ||
260 | */ | ||
261 | crashing_cpu = smp_processor_id(); | ||
262 | crash_kexec_prepare_cpus(); | ||
263 | crash_save_self(regs); | ||
264 | } | ||
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c new file mode 100644 index 000000000000..87effa3f21a7 --- /dev/null +++ b/arch/powerpc/kernel/crash_dump.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * Routines for doing kexec-based kdump. | ||
3 | * | ||
4 | * Copyright (C) 2005, IBM Corp. | ||
5 | * | ||
6 | * Created by: Michael Ellerman | ||
7 | * | ||
8 | * This source code is licensed under the GNU General Public License, | ||
9 | * Version 2. See the file COPYING for more details. | ||
10 | */ | ||
11 | |||
12 | #undef DEBUG | ||
13 | |||
14 | #include <linux/crash_dump.h> | ||
15 | #include <linux/bootmem.h> | ||
16 | #include <asm/kdump.h> | ||
17 | #include <asm/lmb.h> | ||
18 | #include <asm/firmware.h> | ||
19 | #include <asm/uaccess.h> | ||
20 | |||
21 | #ifdef DEBUG | ||
22 | #include <asm/udbg.h> | ||
23 | #define DBG(fmt...) udbg_printf(fmt) | ||
24 | #else | ||
25 | #define DBG(fmt...) | ||
26 | #endif | ||
27 | |||
28 | static void __init create_trampoline(unsigned long addr) | ||
29 | { | ||
30 | /* The maximum range of a single instruction branch, is the current | ||
31 | * instruction's address + (32 MB - 4) bytes. For the trampoline we | ||
32 | * need to branch to current address + 32 MB. So we insert a nop at | ||
33 | * the trampoline address, then the next instruction (+ 4 bytes) | ||
34 | * does a branch to (32 MB - 4). The net effect is that when we | ||
35 | * branch to "addr" we jump to ("addr" + 32 MB). Although it requires | ||
36 | * two instructions it doesn't require any registers. | ||
37 | */ | ||
38 | create_instruction(addr, 0x60000000); /* nop */ | ||
39 | create_branch(addr + 4, addr + PHYSICAL_START, 0); | ||
40 | } | ||
41 | |||
42 | void __init kdump_setup(void) | ||
43 | { | ||
44 | unsigned long i; | ||
45 | |||
46 | DBG(" -> kdump_setup()\n"); | ||
47 | |||
48 | for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) { | ||
49 | create_trampoline(i); | ||
50 | } | ||
51 | |||
52 | create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); | ||
53 | create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); | ||
54 | |||
55 | DBG(" <- kdump_setup()\n"); | ||
56 | } | ||
57 | |||
58 | static int __init parse_elfcorehdr(char *p) | ||
59 | { | ||
60 | if (p) | ||
61 | elfcorehdr_addr = memparse(p, &p); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | __setup("elfcorehdr=", parse_elfcorehdr); | ||
66 | |||
67 | static int __init parse_savemaxmem(char *p) | ||
68 | { | ||
69 | if (p) | ||
70 | saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | __setup("savemaxmem=", parse_savemaxmem); | ||
75 | |||
76 | /* | ||
77 | * copy_oldmem_page - copy one page from "oldmem" | ||
78 | * @pfn: page frame number to be copied | ||
79 | * @buf: target memory address for the copy; this can be in kernel address | ||
80 | * space or user address space (see @userbuf) | ||
81 | * @csize: number of bytes to copy | ||
82 | * @offset: offset in bytes into the page (based on pfn) to begin the copy | ||
83 | * @userbuf: if set, @buf is in user address space, use copy_to_user(), | ||
84 | * otherwise @buf is in kernel address space, use memcpy(). | ||
85 | * | ||
86 | * Copy a page from "oldmem". For this page, there is no pte mapped | ||
87 | * in the current kernel. We stitch up a pte, similar to kmap_atomic. | ||
88 | */ | ||
89 | ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | ||
90 | size_t csize, unsigned long offset, int userbuf) | ||
91 | { | ||
92 | void *vaddr; | ||
93 | |||
94 | if (!csize) | ||
95 | return 0; | ||
96 | |||
97 | vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0); | ||
98 | |||
99 | if (userbuf) { | ||
100 | if (copy_to_user((char __user *)buf, (vaddr + offset), csize)) { | ||
101 | iounmap(vaddr); | ||
102 | return -EFAULT; | ||
103 | } | ||
104 | } else | ||
105 | memcpy(buf, (vaddr + offset), csize); | ||
106 | |||
107 | iounmap(vaddr); | ||
108 | return csize; | ||
109 | } | ||
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 7c3419656ccc..36aaa7663f02 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c | |||
@@ -10,6 +10,7 @@ | |||
10 | /* Include the busses we support */ | 10 | /* Include the busses we support */ |
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | #include <asm/vio.h> | 12 | #include <asm/vio.h> |
13 | #include <asm/ibmebus.h> | ||
13 | #include <asm/scatterlist.h> | 14 | #include <asm/scatterlist.h> |
14 | #include <asm/bug.h> | 15 | #include <asm/bug.h> |
15 | 16 | ||
@@ -23,6 +24,10 @@ static struct dma_mapping_ops *get_dma_ops(struct device *dev) | |||
23 | if (dev->bus == &vio_bus_type) | 24 | if (dev->bus == &vio_bus_type) |
24 | return &vio_dma_ops; | 25 | return &vio_dma_ops; |
25 | #endif | 26 | #endif |
27 | #ifdef CONFIG_IBMEBUS | ||
28 | if (dev->bus == &ibmebus_bus_type) | ||
29 | return &ibmebus_dma_ops; | ||
30 | #endif | ||
26 | return NULL; | 31 | return NULL; |
27 | } | 32 | } |
28 | 33 | ||
@@ -47,6 +52,10 @@ int dma_set_mask(struct device *dev, u64 dma_mask) | |||
47 | if (dev->bus == &vio_bus_type) | 52 | if (dev->bus == &vio_bus_type) |
48 | return -EIO; | 53 | return -EIO; |
49 | #endif /* CONFIG_IBMVIO */ | 54 | #endif /* CONFIG_IBMVIO */ |
55 | #ifdef CONFIG_IBMEBUS | ||
56 | if (dev->bus == &ibmebus_bus_type) | ||
57 | return -EIO; | ||
58 | #endif | ||
50 | BUG(); | 59 | BUG(); |
51 | return 0; | 60 | return 0; |
52 | } | 61 | } |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 2e99ae41723c..036b71d2adfc 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -200,8 +200,6 @@ _GLOBAL(DoSyscall) | |||
200 | bl do_show_syscall | 200 | bl do_show_syscall |
201 | #endif /* SHOW_SYSCALLS */ | 201 | #endif /* SHOW_SYSCALLS */ |
202 | rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | 202 | rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ |
203 | li r11,0 | ||
204 | stb r11,TI_SC_NOERR(r10) | ||
205 | lwz r11,TI_FLAGS(r10) | 203 | lwz r11,TI_FLAGS(r10) |
206 | andi. r11,r11,_TIF_SYSCALL_T_OR_A | 204 | andi. r11,r11,_TIF_SYSCALL_T_OR_A |
207 | bne- syscall_dotrace | 205 | bne- syscall_dotrace |
@@ -222,25 +220,21 @@ ret_from_syscall: | |||
222 | bl do_show_syscall_exit | 220 | bl do_show_syscall_exit |
223 | #endif | 221 | #endif |
224 | mr r6,r3 | 222 | mr r6,r3 |
225 | li r11,-_LAST_ERRNO | ||
226 | cmplw 0,r3,r11 | ||
227 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | 223 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ |
228 | blt+ 30f | ||
229 | lbz r11,TI_SC_NOERR(r12) | ||
230 | cmpwi r11,0 | ||
231 | bne 30f | ||
232 | neg r3,r3 | ||
233 | lwz r10,_CCR(r1) /* Set SO bit in CR */ | ||
234 | oris r10,r10,0x1000 | ||
235 | stw r10,_CCR(r1) | ||
236 | |||
237 | /* disable interrupts so current_thread_info()->flags can't change */ | 224 | /* disable interrupts so current_thread_info()->flags can't change */ |
238 | 30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ | 225 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ |
239 | SYNC | 226 | SYNC |
240 | MTMSRD(r10) | 227 | MTMSRD(r10) |
241 | lwz r9,TI_FLAGS(r12) | 228 | lwz r9,TI_FLAGS(r12) |
242 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 229 | li r8,-_LAST_ERRNO |
230 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) | ||
243 | bne- syscall_exit_work | 231 | bne- syscall_exit_work |
232 | cmplw 0,r3,r8 | ||
233 | blt+ syscall_exit_cont | ||
234 | lwz r11,_CCR(r1) /* Load CR */ | ||
235 | neg r3,r3 | ||
236 | oris r11,r11,0x1000 /* Set SO bit in CR */ | ||
237 | stw r11,_CCR(r1) | ||
244 | syscall_exit_cont: | 238 | syscall_exit_cont: |
245 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 239 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) |
246 | /* If the process has its own DBCR0 value, load it up. The single | 240 | /* If the process has its own DBCR0 value, load it up. The single |
@@ -292,46 +286,113 @@ syscall_dotrace: | |||
292 | b syscall_dotrace_cont | 286 | b syscall_dotrace_cont |
293 | 287 | ||
294 | syscall_exit_work: | 288 | syscall_exit_work: |
295 | stw r6,RESULT(r1) /* Save result */ | 289 | andi. r0,r9,_TIF_RESTOREALL |
290 | bne- 2f | ||
291 | cmplw 0,r3,r8 | ||
292 | blt+ 1f | ||
293 | andi. r0,r9,_TIF_NOERROR | ||
294 | bne- 1f | ||
295 | lwz r11,_CCR(r1) /* Load CR */ | ||
296 | neg r3,r3 | ||
297 | oris r11,r11,0x1000 /* Set SO bit in CR */ | ||
298 | stw r11,_CCR(r1) | ||
299 | |||
300 | 1: stw r6,RESULT(r1) /* Save result */ | ||
296 | stw r3,GPR3(r1) /* Update return value */ | 301 | stw r3,GPR3(r1) /* Update return value */ |
297 | andi. r0,r9,_TIF_SYSCALL_T_OR_A | 302 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) |
298 | beq 5f | 303 | beq 4f |
299 | ori r10,r10,MSR_EE | 304 | |
300 | SYNC | 305 | /* Clear per-syscall TIF flags if any are set, but _leave_ |
301 | MTMSRD(r10) /* re-enable interrupts */ | 306 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that |
307 | yet. */ | ||
308 | |||
309 | li r11,_TIF_PERSYSCALL_MASK | ||
310 | addi r12,r12,TI_FLAGS | ||
311 | 3: lwarx r8,0,r12 | ||
312 | andc r8,r8,r11 | ||
313 | #ifdef CONFIG_IBM405_ERR77 | ||
314 | dcbt 0,r12 | ||
315 | #endif | ||
316 | stwcx. r8,0,r12 | ||
317 | bne- 3b | ||
318 | subi r12,r12,TI_FLAGS | ||
319 | |||
320 | 4: /* Anything which requires enabling interrupts? */ | ||
321 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | ||
322 | beq 7f | ||
323 | |||
324 | /* Save NVGPRS if they're not saved already */ | ||
302 | lwz r4,_TRAP(r1) | 325 | lwz r4,_TRAP(r1) |
303 | andi. r4,r4,1 | 326 | andi. r4,r4,1 |
304 | beq 4f | 327 | beq 5f |
305 | SAVE_NVGPRS(r1) | 328 | SAVE_NVGPRS(r1) |
306 | li r4,0xc00 | 329 | li r4,0xc00 |
307 | stw r4,_TRAP(r1) | 330 | stw r4,_TRAP(r1) |
308 | 4: | 331 | |
332 | /* Re-enable interrupts */ | ||
333 | 5: ori r10,r10,MSR_EE | ||
334 | SYNC | ||
335 | MTMSRD(r10) | ||
336 | |||
337 | andi. r0,r9,_TIF_SAVE_NVGPRS | ||
338 | bne save_user_nvgprs | ||
339 | |||
340 | save_user_nvgprs_cont: | ||
341 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
342 | beq 7f | ||
343 | |||
309 | addi r3,r1,STACK_FRAME_OVERHEAD | 344 | addi r3,r1,STACK_FRAME_OVERHEAD |
310 | bl do_syscall_trace_leave | 345 | bl do_syscall_trace_leave |
311 | REST_NVGPRS(r1) | 346 | REST_NVGPRS(r1) |
312 | 2: | 347 | |
313 | lwz r3,GPR3(r1) | 348 | 6: lwz r3,GPR3(r1) |
314 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ | 349 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ |
315 | SYNC | 350 | SYNC |
316 | MTMSRD(r10) /* disable interrupts again */ | 351 | MTMSRD(r10) /* disable interrupts again */ |
317 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | 352 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ |
318 | lwz r9,TI_FLAGS(r12) | 353 | lwz r9,TI_FLAGS(r12) |
319 | 5: | 354 | 7: |
320 | andi. r0,r9,_TIF_NEED_RESCHED | 355 | andi. r0,r9,_TIF_NEED_RESCHED |
321 | bne 1f | 356 | bne 8f |
322 | lwz r5,_MSR(r1) | 357 | lwz r5,_MSR(r1) |
323 | andi. r5,r5,MSR_PR | 358 | andi. r5,r5,MSR_PR |
324 | beq syscall_exit_cont | 359 | beq ret_from_except |
325 | andi. r0,r9,_TIF_SIGPENDING | 360 | andi. r0,r9,_TIF_SIGPENDING |
326 | beq syscall_exit_cont | 361 | beq ret_from_except |
327 | b do_user_signal | 362 | b do_user_signal |
328 | 1: | 363 | 8: |
329 | ori r10,r10,MSR_EE | 364 | ori r10,r10,MSR_EE |
330 | SYNC | 365 | SYNC |
331 | MTMSRD(r10) /* re-enable interrupts */ | 366 | MTMSRD(r10) /* re-enable interrupts */ |
332 | bl schedule | 367 | bl schedule |
333 | b 2b | 368 | b 6b |
369 | |||
370 | save_user_nvgprs: | ||
371 | lwz r8,TI_SIGFRAME(r12) | ||
372 | |||
373 | .macro savewords start, end | ||
374 | 1: stw \start,4*(\start)(r8) | ||
375 | .section __ex_table,"a" | ||
376 | .align 2 | ||
377 | .long 1b,save_user_nvgprs_fault | ||
378 | .previous | ||
379 | .if \end - \start | ||
380 | savewords "(\start+1)",\end | ||
381 | .endif | ||
382 | .endm | ||
383 | savewords 14,31 | ||
384 | b save_user_nvgprs_cont | ||
385 | |||
386 | |||
387 | save_user_nvgprs_fault: | ||
388 | li r3,11 /* SIGSEGV */ | ||
389 | lwz r4,TI_TASK(r12) | ||
390 | bl force_sigsegv | ||
334 | 391 | ||
392 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | ||
393 | lwz r9,TI_FLAGS(r12) | ||
394 | b save_user_nvgprs_cont | ||
395 | |||
335 | #ifdef SHOW_SYSCALLS | 396 | #ifdef SHOW_SYSCALLS |
336 | do_show_syscall: | 397 | do_show_syscall: |
337 | #ifdef SHOW_SYSCALLS_TASK | 398 | #ifdef SHOW_SYSCALLS_TASK |
@@ -401,28 +462,10 @@ show_syscalls_task: | |||
401 | #endif /* SHOW_SYSCALLS */ | 462 | #endif /* SHOW_SYSCALLS */ |
402 | 463 | ||
403 | /* | 464 | /* |
404 | * The sigsuspend and rt_sigsuspend system calls can call do_signal | 465 | * The fork/clone functions need to copy the full register set into |
405 | * and thus put the process into the stopped state where we might | 466 | * the child process. Therefore we need to save all the nonvolatile |
406 | * want to examine its user state with ptrace. Therefore we need | 467 | * registers (r13 - r31) before calling the C code. |
407 | * to save all the nonvolatile registers (r13 - r31) before calling | ||
408 | * the C code. | ||
409 | */ | 468 | */ |
410 | .globl ppc_sigsuspend | ||
411 | ppc_sigsuspend: | ||
412 | SAVE_NVGPRS(r1) | ||
413 | lwz r0,_TRAP(r1) | ||
414 | rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ | ||
415 | stw r0,_TRAP(r1) /* register set saved */ | ||
416 | b sys_sigsuspend | ||
417 | |||
418 | .globl ppc_rt_sigsuspend | ||
419 | ppc_rt_sigsuspend: | ||
420 | SAVE_NVGPRS(r1) | ||
421 | lwz r0,_TRAP(r1) | ||
422 | rlwinm r0,r0,0,0,30 | ||
423 | stw r0,_TRAP(r1) | ||
424 | b sys_rt_sigsuspend | ||
425 | |||
426 | .globl ppc_fork | 469 | .globl ppc_fork |
427 | ppc_fork: | 470 | ppc_fork: |
428 | SAVE_NVGPRS(r1) | 471 | SAVE_NVGPRS(r1) |
@@ -447,14 +490,6 @@ ppc_clone: | |||
447 | stw r0,_TRAP(r1) /* register set saved */ | 490 | stw r0,_TRAP(r1) /* register set saved */ |
448 | b sys_clone | 491 | b sys_clone |
449 | 492 | ||
450 | .globl ppc_swapcontext | ||
451 | ppc_swapcontext: | ||
452 | SAVE_NVGPRS(r1) | ||
453 | lwz r0,_TRAP(r1) | ||
454 | rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ | ||
455 | stw r0,_TRAP(r1) /* register set saved */ | ||
456 | b sys_swapcontext | ||
457 | |||
458 | /* | 493 | /* |
459 | * Top-level page fault handling. | 494 | * Top-level page fault handling. |
460 | * This is in assembler because if do_page_fault tells us that | 495 | * This is in assembler because if do_page_fault tells us that |
@@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) | |||
626 | .long ret_from_except | 661 | .long ret_from_except |
627 | #endif | 662 | #endif |
628 | 663 | ||
629 | .globl sigreturn_exit | ||
630 | sigreturn_exit: | ||
631 | subi r1,r3,STACK_FRAME_OVERHEAD | ||
632 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | ||
633 | lwz r9,TI_FLAGS(r12) | ||
634 | andi. r0,r9,_TIF_SYSCALL_T_OR_A | ||
635 | beq+ ret_from_except_full | ||
636 | bl do_syscall_trace_leave | ||
637 | /* fall through */ | ||
638 | |||
639 | .globl ret_from_except_full | 664 | .globl ret_from_except_full |
640 | ret_from_except_full: | 665 | ret_from_except_full: |
641 | REST_NVGPRS(r1) | 666 | REST_NVGPRS(r1) |
@@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ | |||
658 | /* Check current_thread_info()->flags */ | 683 | /* Check current_thread_info()->flags */ |
659 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) | 684 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) |
660 | lwz r9,TI_FLAGS(r9) | 685 | lwz r9,TI_FLAGS(r9) |
661 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 686 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) |
662 | bne do_work | 687 | bne do_work |
663 | 688 | ||
664 | restore_user: | 689 | restore_user: |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bce33a38399f..aacebb33e98a 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -113,9 +113,7 @@ system_call_common: | |||
113 | addi r9,r1,STACK_FRAME_OVERHEAD | 113 | addi r9,r1,STACK_FRAME_OVERHEAD |
114 | #endif | 114 | #endif |
115 | clrrdi r11,r1,THREAD_SHIFT | 115 | clrrdi r11,r1,THREAD_SHIFT |
116 | li r12,0 | ||
117 | ld r10,TI_FLAGS(r11) | 116 | ld r10,TI_FLAGS(r11) |
118 | stb r12,TI_SC_NOERR(r11) | ||
119 | andi. r11,r10,_TIF_SYSCALL_T_OR_A | 117 | andi. r11,r10,_TIF_SYSCALL_T_OR_A |
120 | bne- syscall_dotrace | 118 | bne- syscall_dotrace |
121 | syscall_dotrace_cont: | 119 | syscall_dotrace_cont: |
@@ -144,24 +142,12 @@ system_call: /* label this so stack traces look sane */ | |||
144 | bctrl /* Call handler */ | 142 | bctrl /* Call handler */ |
145 | 143 | ||
146 | syscall_exit: | 144 | syscall_exit: |
145 | std r3,RESULT(r1) | ||
147 | #ifdef SHOW_SYSCALLS | 146 | #ifdef SHOW_SYSCALLS |
148 | std r3,GPR3(r1) | ||
149 | bl .do_show_syscall_exit | 147 | bl .do_show_syscall_exit |
150 | ld r3,GPR3(r1) | 148 | ld r3,RESULT(r1) |
151 | #endif | 149 | #endif |
152 | std r3,RESULT(r1) | ||
153 | ld r5,_CCR(r1) | ||
154 | li r10,-_LAST_ERRNO | ||
155 | cmpld r3,r10 | ||
156 | clrrdi r12,r1,THREAD_SHIFT | 150 | clrrdi r12,r1,THREAD_SHIFT |
157 | bge- syscall_error | ||
158 | syscall_error_cont: | ||
159 | |||
160 | /* check for syscall tracing or audit */ | ||
161 | ld r9,TI_FLAGS(r12) | ||
162 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
163 | bne- syscall_exit_trace | ||
164 | syscall_exit_trace_cont: | ||
165 | 151 | ||
166 | /* disable interrupts so current_thread_info()->flags can't change, | 152 | /* disable interrupts so current_thread_info()->flags can't change, |
167 | and so that we don't get interrupted after loading SRR0/1. */ | 153 | and so that we don't get interrupted after loading SRR0/1. */ |
@@ -173,8 +159,13 @@ syscall_exit_trace_cont: | |||
173 | rotldi r10,r10,16 | 159 | rotldi r10,r10,16 |
174 | mtmsrd r10,1 | 160 | mtmsrd r10,1 |
175 | ld r9,TI_FLAGS(r12) | 161 | ld r9,TI_FLAGS(r12) |
176 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 162 | li r11,-_LAST_ERRNO |
163 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR) | ||
177 | bne- syscall_exit_work | 164 | bne- syscall_exit_work |
165 | cmpld r3,r11 | ||
166 | ld r5,_CCR(r1) | ||
167 | bge- syscall_error | ||
168 | syscall_error_cont: | ||
178 | ld r7,_NIP(r1) | 169 | ld r7,_NIP(r1) |
179 | stdcx. r0,0,r1 /* to clear the reservation */ | 170 | stdcx. r0,0,r1 /* to clear the reservation */ |
180 | andi. r6,r8,MSR_PR | 171 | andi. r6,r8,MSR_PR |
@@ -193,21 +184,12 @@ syscall_exit_trace_cont: | |||
193 | rfid | 184 | rfid |
194 | b . /* prevent speculative execution */ | 185 | b . /* prevent speculative execution */ |
195 | 186 | ||
196 | syscall_enosys: | 187 | syscall_error: |
197 | li r3,-ENOSYS | ||
198 | std r3,RESULT(r1) | ||
199 | clrrdi r12,r1,THREAD_SHIFT | ||
200 | ld r5,_CCR(r1) | ||
201 | |||
202 | syscall_error: | ||
203 | lbz r11,TI_SC_NOERR(r12) | ||
204 | cmpwi 0,r11,0 | ||
205 | bne- syscall_error_cont | ||
206 | neg r3,r3 | ||
207 | oris r5,r5,0x1000 /* Set SO bit in CR */ | 188 | oris r5,r5,0x1000 /* Set SO bit in CR */ |
189 | neg r3,r3 | ||
208 | std r5,_CCR(r1) | 190 | std r5,_CCR(r1) |
209 | b syscall_error_cont | 191 | b syscall_error_cont |
210 | 192 | ||
211 | /* Traced system call support */ | 193 | /* Traced system call support */ |
212 | syscall_dotrace: | 194 | syscall_dotrace: |
213 | bl .save_nvgprs | 195 | bl .save_nvgprs |
@@ -225,21 +207,69 @@ syscall_dotrace: | |||
225 | ld r10,TI_FLAGS(r10) | 207 | ld r10,TI_FLAGS(r10) |
226 | b syscall_dotrace_cont | 208 | b syscall_dotrace_cont |
227 | 209 | ||
228 | syscall_exit_trace: | 210 | syscall_enosys: |
229 | std r3,GPR3(r1) | 211 | li r3,-ENOSYS |
230 | bl .save_nvgprs | 212 | b syscall_exit |
213 | |||
214 | syscall_exit_work: | ||
215 | /* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr. | ||
216 | If TIF_NOERROR is set, just save r3 as it is. */ | ||
217 | |||
218 | andi. r0,r9,_TIF_RESTOREALL | ||
219 | bne- 2f | ||
220 | cmpld r3,r11 /* r10 is -LAST_ERRNO */ | ||
221 | blt+ 1f | ||
222 | andi. r0,r9,_TIF_NOERROR | ||
223 | bne- 1f | ||
224 | ld r5,_CCR(r1) | ||
225 | neg r3,r3 | ||
226 | oris r5,r5,0x1000 /* Set SO bit in CR */ | ||
227 | std r5,_CCR(r1) | ||
228 | 1: std r3,GPR3(r1) | ||
229 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) | ||
230 | beq 4f | ||
231 | |||
232 | /* Clear per-syscall TIF flags if any are set, but _leave_ | ||
233 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that | ||
234 | yet. */ | ||
235 | |||
236 | li r11,_TIF_PERSYSCALL_MASK | ||
237 | addi r12,r12,TI_FLAGS | ||
238 | 3: ldarx r10,0,r12 | ||
239 | andc r10,r10,r11 | ||
240 | stdcx. r10,0,r12 | ||
241 | bne- 3b | ||
242 | subi r12,r12,TI_FLAGS | ||
243 | |||
244 | 4: bl .save_nvgprs | ||
245 | /* Anything else left to do? */ | ||
246 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | ||
247 | beq .ret_from_except_lite | ||
248 | |||
249 | /* Re-enable interrupts */ | ||
250 | mfmsr r10 | ||
251 | ori r10,r10,MSR_EE | ||
252 | mtmsrd r10,1 | ||
253 | |||
254 | andi. r0,r9,_TIF_SAVE_NVGPRS | ||
255 | bne save_user_nvgprs | ||
256 | |||
257 | /* If tracing, re-enable interrupts and do it */ | ||
258 | save_user_nvgprs_cont: | ||
259 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
260 | beq 5f | ||
261 | |||
231 | addi r3,r1,STACK_FRAME_OVERHEAD | 262 | addi r3,r1,STACK_FRAME_OVERHEAD |
232 | bl .do_syscall_trace_leave | 263 | bl .do_syscall_trace_leave |
233 | REST_NVGPRS(r1) | 264 | REST_NVGPRS(r1) |
234 | ld r3,GPR3(r1) | ||
235 | ld r5,_CCR(r1) | ||
236 | clrrdi r12,r1,THREAD_SHIFT | 265 | clrrdi r12,r1,THREAD_SHIFT |
237 | b syscall_exit_trace_cont | ||
238 | 266 | ||
239 | /* Stuff to do on exit from a system call. */ | 267 | /* Disable interrupts again and handle other work if any */ |
240 | syscall_exit_work: | 268 | 5: mfmsr r10 |
241 | std r3,GPR3(r1) | 269 | rldicl r10,r10,48,1 |
242 | std r5,_CCR(r1) | 270 | rotldi r10,r10,16 |
271 | mtmsrd r10,1 | ||
272 | |||
243 | b .ret_from_except_lite | 273 | b .ret_from_except_lite |
244 | 274 | ||
245 | /* Save non-volatile GPRs, if not already saved. */ | 275 | /* Save non-volatile GPRs, if not already saved. */ |
@@ -252,6 +282,52 @@ _GLOBAL(save_nvgprs) | |||
252 | std r0,_TRAP(r1) | 282 | std r0,_TRAP(r1) |
253 | blr | 283 | blr |
254 | 284 | ||
285 | |||
286 | save_user_nvgprs: | ||
287 | ld r10,TI_SIGFRAME(r12) | ||
288 | andi. r0,r9,_TIF_32BIT | ||
289 | beq- save_user_nvgprs_64 | ||
290 | |||
291 | /* 32-bit save to userspace */ | ||
292 | |||
293 | .macro savewords start, end | ||
294 | 1: stw \start,4*(\start)(r10) | ||
295 | .section __ex_table,"a" | ||
296 | .align 3 | ||
297 | .llong 1b,save_user_nvgprs_fault | ||
298 | .previous | ||
299 | .if \end - \start | ||
300 | savewords "(\start+1)",\end | ||
301 | .endif | ||
302 | .endm | ||
303 | savewords 14,31 | ||
304 | b save_user_nvgprs_cont | ||
305 | |||
306 | save_user_nvgprs_64: | ||
307 | /* 64-bit save to userspace */ | ||
308 | |||
309 | .macro savelongs start, end | ||
310 | 1: std \start,8*(\start)(r10) | ||
311 | .section __ex_table,"a" | ||
312 | .align 3 | ||
313 | .llong 1b,save_user_nvgprs_fault | ||
314 | .previous | ||
315 | .if \end - \start | ||
316 | savelongs "(\start+1)",\end | ||
317 | .endif | ||
318 | .endm | ||
319 | savelongs 14,31 | ||
320 | b save_user_nvgprs_cont | ||
321 | |||
322 | save_user_nvgprs_fault: | ||
323 | li r3,11 /* SIGSEGV */ | ||
324 | ld r4,TI_TASK(r12) | ||
325 | bl .force_sigsegv | ||
326 | |||
327 | clrrdi r12,r1,THREAD_SHIFT | ||
328 | ld r9,TI_FLAGS(r12) | ||
329 | b save_user_nvgprs_cont | ||
330 | |||
255 | /* | 331 | /* |
256 | * The sigsuspend and rt_sigsuspend system calls can call do_signal | 332 | * The sigsuspend and rt_sigsuspend system calls can call do_signal |
257 | * and thus put the process into the stopped state where we might | 333 | * and thus put the process into the stopped state where we might |
@@ -260,35 +336,6 @@ _GLOBAL(save_nvgprs) | |||
260 | * the C code. Similarly, fork, vfork and clone need the full | 336 | * the C code. Similarly, fork, vfork and clone need the full |
261 | * register state on the stack so that it can be copied to the child. | 337 | * register state on the stack so that it can be copied to the child. |
262 | */ | 338 | */ |
263 | _GLOBAL(ppc32_sigsuspend) | ||
264 | bl .save_nvgprs | ||
265 | bl .compat_sys_sigsuspend | ||
266 | b 70f | ||
267 | |||
268 | _GLOBAL(ppc64_rt_sigsuspend) | ||
269 | bl .save_nvgprs | ||
270 | bl .sys_rt_sigsuspend | ||
271 | b 70f | ||
272 | |||
273 | _GLOBAL(ppc32_rt_sigsuspend) | ||
274 | bl .save_nvgprs | ||
275 | bl .compat_sys_rt_sigsuspend | ||
276 | 70: cmpdi 0,r3,0 | ||
277 | /* If it returned an error, we need to return via syscall_exit to set | ||
278 | the SO bit in cr0 and potentially stop for ptrace. */ | ||
279 | bne syscall_exit | ||
280 | /* If sigsuspend() returns zero, we are going into a signal handler. We | ||
281 | may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ | ||
282 | #ifdef CONFIG_AUDITSYSCALL | ||
283 | ld r3,PACACURRENT(r13) | ||
284 | ld r4,AUDITCONTEXT(r3) | ||
285 | cmpdi 0,r4,0 | ||
286 | beq .ret_from_except /* No audit_context: Leave immediately. */ | ||
287 | li r4, 2 /* AUDITSC_FAILURE */ | ||
288 | li r5,-4 /* It's always -EINTR */ | ||
289 | bl .audit_syscall_exit | ||
290 | #endif | ||
291 | b .ret_from_except | ||
292 | 339 | ||
293 | _GLOBAL(ppc_fork) | 340 | _GLOBAL(ppc_fork) |
294 | bl .save_nvgprs | 341 | bl .save_nvgprs |
@@ -305,37 +352,6 @@ _GLOBAL(ppc_clone) | |||
305 | bl .sys_clone | 352 | bl .sys_clone |
306 | b syscall_exit | 353 | b syscall_exit |
307 | 354 | ||
308 | _GLOBAL(ppc32_swapcontext) | ||
309 | bl .save_nvgprs | ||
310 | bl .compat_sys_swapcontext | ||
311 | b 80f | ||
312 | |||
313 | _GLOBAL(ppc64_swapcontext) | ||
314 | bl .save_nvgprs | ||
315 | bl .sys_swapcontext | ||
316 | b 80f | ||
317 | |||
318 | _GLOBAL(ppc32_sigreturn) | ||
319 | bl .compat_sys_sigreturn | ||
320 | b 80f | ||
321 | |||
322 | _GLOBAL(ppc32_rt_sigreturn) | ||
323 | bl .compat_sys_rt_sigreturn | ||
324 | b 80f | ||
325 | |||
326 | _GLOBAL(ppc64_rt_sigreturn) | ||
327 | bl .sys_rt_sigreturn | ||
328 | |||
329 | 80: cmpdi 0,r3,0 | ||
330 | blt syscall_exit | ||
331 | clrrdi r4,r1,THREAD_SHIFT | ||
332 | ld r4,TI_FLAGS(r4) | ||
333 | andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
334 | beq+ 81f | ||
335 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
336 | bl .do_syscall_trace_leave | ||
337 | 81: b .ret_from_except | ||
338 | |||
339 | _GLOBAL(ret_from_fork) | 355 | _GLOBAL(ret_from_fork) |
340 | bl .schedule_tail | 356 | bl .schedule_tail |
341 | REST_NVGPRS(r1) | 357 | REST_NVGPRS(r1) |
@@ -674,7 +690,7 @@ _GLOBAL(enter_rtas) | |||
674 | 690 | ||
675 | /* Setup our real return addr */ | 691 | /* Setup our real return addr */ |
676 | SET_REG_TO_LABEL(r4,.rtas_return_loc) | 692 | SET_REG_TO_LABEL(r4,.rtas_return_loc) |
677 | SET_REG_TO_CONST(r9,KERNELBASE) | 693 | SET_REG_TO_CONST(r9,PAGE_OFFSET) |
678 | sub r4,r4,r9 | 694 | sub r4,r4,r9 |
679 | mtlr r4 | 695 | mtlr r4 |
680 | 696 | ||
@@ -702,7 +718,7 @@ _GLOBAL(enter_rtas) | |||
702 | _STATIC(rtas_return_loc) | 718 | _STATIC(rtas_return_loc) |
703 | /* relocation is off at this point */ | 719 | /* relocation is off at this point */ |
704 | mfspr r4,SPRN_SPRG3 /* Get PACA */ | 720 | mfspr r4,SPRN_SPRG3 /* Get PACA */ |
705 | SET_REG_TO_CONST(r5, KERNELBASE) | 721 | SET_REG_TO_CONST(r5, PAGE_OFFSET) |
706 | sub r4,r4,r5 /* RELOC the PACA base pointer */ | 722 | sub r4,r4,r5 /* RELOC the PACA base pointer */ |
707 | 723 | ||
708 | mfmsr r6 | 724 | mfmsr r6 |
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index ccdf94731e30..03b25f9359f8 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S | |||
@@ -120,10 +120,25 @@ __start: | |||
120 | * because OF may have I/O devices mapped into that area | 120 | * because OF may have I/O devices mapped into that area |
121 | * (particularly on CHRP). | 121 | * (particularly on CHRP). |
122 | */ | 122 | */ |
123 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
123 | cmpwi 0,r5,0 | 124 | cmpwi 0,r5,0 |
124 | beq 1f | 125 | beq 1f |
125 | bl prom_init | 126 | bl prom_init |
126 | trap | 127 | trap |
128 | #endif | ||
129 | |||
130 | /* | ||
131 | * Check for BootX signature when supporting PowerMac and branch to | ||
132 | * appropriate trampoline if it's present | ||
133 | */ | ||
134 | #ifdef CONFIG_PPC_PMAC | ||
135 | 1: lis r31,0x426f | ||
136 | ori r31,r31,0x6f58 | ||
137 | cmpw 0,r3,r31 | ||
138 | bne 1f | ||
139 | bl bootx_init | ||
140 | trap | ||
141 | #endif /* CONFIG_PPC_PMAC */ | ||
127 | 142 | ||
128 | 1: mr r31,r3 /* save parameters */ | 143 | 1: mr r31,r3 /* save parameters */ |
129 | mr r30,r4 | 144 | mr r30,r4 |
@@ -153,6 +168,9 @@ __after_mmu_off: | |||
153 | bl flush_tlbs | 168 | bl flush_tlbs |
154 | 169 | ||
155 | bl initial_bats | 170 | bl initial_bats |
171 | #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) | ||
172 | bl setup_disp_bat | ||
173 | #endif | ||
156 | 174 | ||
157 | /* | 175 | /* |
158 | * Call setup_cpu for CPU 0 and initialize 6xx Idle | 176 | * Call setup_cpu for CPU 0 and initialize 6xx Idle |
@@ -450,16 +468,11 @@ SystemCall: | |||
450 | * by executing an altivec instruction. | 468 | * by executing an altivec instruction. |
451 | */ | 469 | */ |
452 | . = 0xf00 | 470 | . = 0xf00 |
453 | b Trap_0f | 471 | b PerformanceMonitor |
454 | 472 | ||
455 | . = 0xf20 | 473 | . = 0xf20 |
456 | b AltiVecUnavailable | 474 | b AltiVecUnavailable |
457 | 475 | ||
458 | Trap_0f: | ||
459 | EXCEPTION_PROLOG | ||
460 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
461 | EXC_XFER_EE(0xf00, unknown_exception) | ||
462 | |||
463 | /* | 476 | /* |
464 | * Handle TLB miss for instruction on 603/603e. | 477 | * Handle TLB miss for instruction on 603/603e. |
465 | * Note: we get an alternate set of r0 - r3 to use automatically. | 478 | * Note: we get an alternate set of r0 - r3 to use automatically. |
@@ -703,6 +716,11 @@ AltiVecUnavailable: | |||
703 | #endif /* CONFIG_ALTIVEC */ | 716 | #endif /* CONFIG_ALTIVEC */ |
704 | EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) | 717 | EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) |
705 | 718 | ||
719 | PerformanceMonitor: | ||
720 | EXCEPTION_PROLOG | ||
721 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
722 | EXC_XFER_STD(0xf00, performance_monitor_exception) | ||
723 | |||
706 | #ifdef CONFIG_ALTIVEC | 724 | #ifdef CONFIG_ALTIVEC |
707 | /* Note that the AltiVec support is closely modeled after the FP | 725 | /* Note that the AltiVec support is closely modeled after the FP |
708 | * support. Changes to one are likely to be applicable to the | 726 | * support. Changes to one are likely to be applicable to the |
@@ -1306,6 +1324,32 @@ initial_bats: | |||
1306 | blr | 1324 | blr |
1307 | 1325 | ||
1308 | 1326 | ||
1327 | #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) | ||
1328 | setup_disp_bat: | ||
1329 | /* | ||
1330 | * setup the display bat prepared for us in prom.c | ||
1331 | */ | ||
1332 | mflr r8 | ||
1333 | bl reloc_offset | ||
1334 | mtlr r8 | ||
1335 | addis r8,r3,disp_BAT@ha | ||
1336 | addi r8,r8,disp_BAT@l | ||
1337 | cmpwi cr0,r8,0 | ||
1338 | beqlr | ||
1339 | lwz r11,0(r8) | ||
1340 | lwz r8,4(r8) | ||
1341 | mfspr r9,SPRN_PVR | ||
1342 | rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ | ||
1343 | cmpwi 0,r9,1 | ||
1344 | beq 1f | ||
1345 | mtspr SPRN_DBAT3L,r8 | ||
1346 | mtspr SPRN_DBAT3U,r11 | ||
1347 | blr | ||
1348 | 1: mtspr SPRN_IBAT3L,r8 | ||
1349 | mtspr SPRN_IBAT3U,r11 | ||
1350 | blr | ||
1351 | #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ | ||
1352 | |||
1309 | #ifdef CONFIG_8260 | 1353 | #ifdef CONFIG_8260 |
1310 | /* Jump into the system reset for the rom. | 1354 | /* Jump into the system reset for the rom. |
1311 | * We first disable the MMU, and then jump to the ROM reset address. | 1355 | * We first disable the MMU, and then jump to the ROM reset address. |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 8a8bf79ef044..1c066d125375 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -154,11 +154,15 @@ _GLOBAL(__secondary_hold) | |||
154 | bne 100b | 154 | bne 100b |
155 | 155 | ||
156 | #ifdef CONFIG_HMT | 156 | #ifdef CONFIG_HMT |
157 | b .hmt_init | 157 | LOADADDR(r4, .hmt_init) |
158 | mtctr r4 | ||
159 | bctr | ||
158 | #else | 160 | #else |
159 | #ifdef CONFIG_SMP | 161 | #ifdef CONFIG_SMP |
162 | LOADADDR(r4, .pSeries_secondary_smp_init) | ||
163 | mtctr r4 | ||
160 | mr r3,r24 | 164 | mr r3,r24 |
161 | b .pSeries_secondary_smp_init | 165 | bctr |
162 | #else | 166 | #else |
163 | BUG_OPCODE | 167 | BUG_OPCODE |
164 | #endif | 168 | #endif |
@@ -200,6 +204,20 @@ exception_marker: | |||
200 | #define EX_R3 64 | 204 | #define EX_R3 64 |
201 | #define EX_LR 72 | 205 | #define EX_LR 72 |
202 | 206 | ||
207 | /* | ||
208 | * We're short on space and time in the exception prolog, so we can't use | ||
209 | * the normal LOADADDR macro. Normally we just need the low halfword of the | ||
210 | * address, but for Kdump we need the whole low word. | ||
211 | */ | ||
212 | #ifdef CONFIG_CRASH_DUMP | ||
213 | #define LOAD_HANDLER(reg, label) \ | ||
214 | oris reg,reg,(label)@h; /* virt addr of handler ... */ \ | ||
215 | ori reg,reg,(label)@l; /* .. and the rest */ | ||
216 | #else | ||
217 | #define LOAD_HANDLER(reg, label) \ | ||
218 | ori reg,reg,(label)@l; /* virt addr of handler ... */ | ||
219 | #endif | ||
220 | |||
203 | #define EXCEPTION_PROLOG_PSERIES(area, label) \ | 221 | #define EXCEPTION_PROLOG_PSERIES(area, label) \ |
204 | mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ | 222 | mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ |
205 | std r9,area+EX_R9(r13); /* save r9 - r12 */ \ | 223 | std r9,area+EX_R9(r13); /* save r9 - r12 */ \ |
@@ -212,7 +230,7 @@ exception_marker: | |||
212 | clrrdi r12,r13,32; /* get high part of &label */ \ | 230 | clrrdi r12,r13,32; /* get high part of &label */ \ |
213 | mfmsr r10; \ | 231 | mfmsr r10; \ |
214 | mfspr r11,SPRN_SRR0; /* save SRR0 */ \ | 232 | mfspr r11,SPRN_SRR0; /* save SRR0 */ \ |
215 | ori r12,r12,(label)@l; /* virt addr of handler */ \ | 233 | LOAD_HANDLER(r12,label) \ |
216 | ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ | 234 | ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ |
217 | mtspr SPRN_SRR0,r12; \ | 235 | mtspr SPRN_SRR0,r12; \ |
218 | mfspr r12,SPRN_SRR1; /* and SRR1 */ \ | 236 | mfspr r12,SPRN_SRR1; /* and SRR1 */ \ |
@@ -553,6 +571,7 @@ slb_miss_user_pseries: | |||
553 | * Vectors for the FWNMI option. Share common code. | 571 | * Vectors for the FWNMI option. Share common code. |
554 | */ | 572 | */ |
555 | .globl system_reset_fwnmi | 573 | .globl system_reset_fwnmi |
574 | .align 7 | ||
556 | system_reset_fwnmi: | 575 | system_reset_fwnmi: |
557 | HMT_MEDIUM | 576 | HMT_MEDIUM |
558 | mtspr SPRN_SPRG1,r13 /* save r13 */ | 577 | mtspr SPRN_SPRG1,r13 /* save r13 */ |
@@ -560,6 +579,7 @@ system_reset_fwnmi: | |||
560 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) | 579 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) |
561 | 580 | ||
562 | .globl machine_check_fwnmi | 581 | .globl machine_check_fwnmi |
582 | .align 7 | ||
563 | machine_check_fwnmi: | 583 | machine_check_fwnmi: |
564 | HMT_MEDIUM | 584 | HMT_MEDIUM |
565 | mtspr SPRN_SPRG1,r13 /* save r13 */ | 585 | mtspr SPRN_SPRG1,r13 /* save r13 */ |
@@ -726,7 +746,8 @@ iSeries_secondary_smp_loop: | |||
726 | decrementer_iSeries_masked: | 746 | decrementer_iSeries_masked: |
727 | li r11,1 | 747 | li r11,1 |
728 | stb r11,PACALPPACA+LPPACADECRINT(r13) | 748 | stb r11,PACALPPACA+LPPACADECRINT(r13) |
729 | lwz r12,PACADEFAULTDECR(r13) | 749 | LOADBASE(r12,tb_ticks_per_jiffy) |
750 | lwz r12,OFF(tb_ticks_per_jiffy)(r12) | ||
730 | mtspr SPRN_DEC,r12 | 751 | mtspr SPRN_DEC,r12 |
731 | /* fall through */ | 752 | /* fall through */ |
732 | 753 | ||
@@ -1345,7 +1366,7 @@ _GLOBAL(do_stab_bolted) | |||
1345 | * fixed address (the linker can't compute (u64)&initial_stab >> | 1366 | * fixed address (the linker can't compute (u64)&initial_stab >> |
1346 | * PAGE_SHIFT). | 1367 | * PAGE_SHIFT). |
1347 | */ | 1368 | */ |
1348 | . = STAB0_PHYS_ADDR /* 0x6000 */ | 1369 | . = STAB0_OFFSET /* 0x6000 */ |
1349 | .globl initial_stab | 1370 | .globl initial_stab |
1350 | initial_stab: | 1371 | initial_stab: |
1351 | .space 4096 | 1372 | .space 4096 |
@@ -1485,11 +1506,13 @@ _STATIC(__mmu_off) | |||
1485 | * | 1506 | * |
1486 | */ | 1507 | */ |
1487 | _GLOBAL(__start_initialization_multiplatform) | 1508 | _GLOBAL(__start_initialization_multiplatform) |
1509 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1488 | /* | 1510 | /* |
1489 | * Are we booted from a PROM Of-type client-interface ? | 1511 | * Are we booted from a PROM Of-type client-interface ? |
1490 | */ | 1512 | */ |
1491 | cmpldi cr0,r5,0 | 1513 | cmpldi cr0,r5,0 |
1492 | bne .__boot_from_prom /* yes -> prom */ | 1514 | bne .__boot_from_prom /* yes -> prom */ |
1515 | #endif | ||
1493 | 1516 | ||
1494 | /* Save parameters */ | 1517 | /* Save parameters */ |
1495 | mr r31,r3 | 1518 | mr r31,r3 |
@@ -1510,6 +1533,7 @@ _GLOBAL(__start_initialization_multiplatform) | |||
1510 | bl .__mmu_off | 1533 | bl .__mmu_off |
1511 | b .__after_prom_start | 1534 | b .__after_prom_start |
1512 | 1535 | ||
1536 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1513 | _STATIC(__boot_from_prom) | 1537 | _STATIC(__boot_from_prom) |
1514 | /* Save parameters */ | 1538 | /* Save parameters */ |
1515 | mr r31,r3 | 1539 | mr r31,r3 |
@@ -1542,6 +1566,7 @@ _STATIC(__boot_from_prom) | |||
1542 | bl .prom_init | 1566 | bl .prom_init |
1543 | /* We never return */ | 1567 | /* We never return */ |
1544 | trap | 1568 | trap |
1569 | #endif | ||
1545 | 1570 | ||
1546 | /* | 1571 | /* |
1547 | * At this point, r3 contains the physical address we are running at, | 1572 | * At this point, r3 contains the physical address we are running at, |
@@ -1550,7 +1575,7 @@ _STATIC(__boot_from_prom) | |||
1550 | _STATIC(__after_prom_start) | 1575 | _STATIC(__after_prom_start) |
1551 | 1576 | ||
1552 | /* | 1577 | /* |
1553 | * We need to run with __start at physical address 0. | 1578 | * We need to run with __start at physical address PHYSICAL_START. |
1554 | * This will leave some code in the first 256B of | 1579 | * This will leave some code in the first 256B of |
1555 | * real memory, which are reserved for software use. | 1580 | * real memory, which are reserved for software use. |
1556 | * The remainder of the first page is loaded with the fixed | 1581 | * The remainder of the first page is loaded with the fixed |
@@ -1565,7 +1590,7 @@ _STATIC(__after_prom_start) | |||
1565 | mr r26,r3 | 1590 | mr r26,r3 |
1566 | SET_REG_TO_CONST(r27,KERNELBASE) | 1591 | SET_REG_TO_CONST(r27,KERNELBASE) |
1567 | 1592 | ||
1568 | li r3,0 /* target addr */ | 1593 | LOADADDR(r3, PHYSICAL_START) /* target addr */ |
1569 | 1594 | ||
1570 | // XXX FIXME: Use phys returned by OF (r30) | 1595 | // XXX FIXME: Use phys returned by OF (r30) |
1571 | add r4,r27,r26 /* source addr */ | 1596 | add r4,r27,r26 /* source addr */ |
@@ -1846,7 +1871,7 @@ _STATIC(start_here_multiplatform) | |||
1846 | mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ | 1871 | mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ |
1847 | add r13,r13,r24 /* for this processor. */ | 1872 | add r13,r13,r24 /* for this processor. */ |
1848 | add r13,r13,r26 /* convert to physical addr */ | 1873 | add r13,r13,r26 /* convert to physical addr */ |
1849 | mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */ | 1874 | mtspr SPRN_SPRG3,r13 |
1850 | 1875 | ||
1851 | /* Do very early kernel initializations, including initial hash table, | 1876 | /* Do very early kernel initializations, including initial hash table, |
1852 | * stab and slb setup before we turn on relocation. */ | 1877 | * stab and slb setup before we turn on relocation. */ |
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c new file mode 100644 index 000000000000..e47d40ac6f39 --- /dev/null +++ b/arch/powerpc/kernel/ibmebus.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* | ||
2 | * IBM PowerPC IBM eBus Infrastructure Support. | ||
3 | * | ||
4 | * Copyright (c) 2005 IBM Corporation | ||
5 | * Heiko J Schick <schickhj@de.ibm.com> | ||
6 | * | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * This source code is distributed under a dual license of GPL v2.0 and OpenIB | ||
10 | * BSD. | ||
11 | * | ||
12 | * OpenIB BSD License | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or without | ||
15 | * modification, are permitted provided that the following conditions are met: | ||
16 | * | ||
17 | * Redistributions of source code must retain the above copyright notice, this | ||
18 | * list of conditions and the following disclaimer. | ||
19 | * | ||
20 | * Redistributions in binary form must reproduce the above copyright notice, | ||
21 | * this list of conditions and the following disclaimer in the documentation | ||
22 | * and/or other materials | ||
23 | * provided with the distribution. | ||
24 | * | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
32 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||
33 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
35 | * POSSIBILITY OF SUCH DAMAGE. | ||
36 | */ | ||
37 | |||
38 | #include <linux/init.h> | ||
39 | #include <linux/console.h> | ||
40 | #include <linux/kobject.h> | ||
41 | #include <linux/dma-mapping.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <asm/ibmebus.h> | ||
44 | #include <asm/abs_addr.h> | ||
45 | |||
46 | static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */ | ||
47 | .name = ibmebus_bus_device.ofdev.dev.bus_id, | ||
48 | .ofdev.dev.bus_id = "ibmebus", | ||
49 | .ofdev.dev.bus = &ibmebus_bus_type, | ||
50 | }; | ||
51 | |||
52 | static void *ibmebus_alloc_coherent(struct device *dev, | ||
53 | size_t size, | ||
54 | dma_addr_t *dma_handle, | ||
55 | gfp_t flag) | ||
56 | { | ||
57 | void *mem; | ||
58 | |||
59 | mem = kmalloc(size, flag); | ||
60 | *dma_handle = (dma_addr_t)mem; | ||
61 | |||
62 | return mem; | ||
63 | } | ||
64 | |||
65 | static void ibmebus_free_coherent(struct device *dev, | ||
66 | size_t size, void *vaddr, | ||
67 | dma_addr_t dma_handle) | ||
68 | { | ||
69 | kfree(vaddr); | ||
70 | } | ||
71 | |||
72 | static dma_addr_t ibmebus_map_single(struct device *dev, | ||
73 | void *ptr, | ||
74 | size_t size, | ||
75 | enum dma_data_direction direction) | ||
76 | { | ||
77 | return (dma_addr_t)(ptr); | ||
78 | } | ||
79 | |||
80 | static void ibmebus_unmap_single(struct device *dev, | ||
81 | dma_addr_t dma_addr, | ||
82 | size_t size, | ||
83 | enum dma_data_direction direction) | ||
84 | { | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | static int ibmebus_map_sg(struct device *dev, | ||
89 | struct scatterlist *sg, | ||
90 | int nents, enum dma_data_direction direction) | ||
91 | { | ||
92 | int i; | ||
93 | |||
94 | for (i = 0; i < nents; i++) { | ||
95 | sg[i].dma_address = (dma_addr_t)page_address(sg[i].page) | ||
96 | + sg[i].offset; | ||
97 | sg[i].dma_length = sg[i].length; | ||
98 | } | ||
99 | |||
100 | return nents; | ||
101 | } | ||
102 | |||
103 | static void ibmebus_unmap_sg(struct device *dev, | ||
104 | struct scatterlist *sg, | ||
105 | int nents, enum dma_data_direction direction) | ||
106 | { | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | static int ibmebus_dma_supported(struct device *dev, u64 mask) | ||
111 | { | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | struct dma_mapping_ops ibmebus_dma_ops = { | ||
116 | .alloc_coherent = ibmebus_alloc_coherent, | ||
117 | .free_coherent = ibmebus_free_coherent, | ||
118 | .map_single = ibmebus_map_single, | ||
119 | .unmap_single = ibmebus_unmap_single, | ||
120 | .map_sg = ibmebus_map_sg, | ||
121 | .unmap_sg = ibmebus_unmap_sg, | ||
122 | .dma_supported = ibmebus_dma_supported, | ||
123 | }; | ||
124 | |||
125 | static int ibmebus_bus_probe(struct device *dev) | ||
126 | { | ||
127 | struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); | ||
128 | struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); | ||
129 | const struct of_device_id *id; | ||
130 | int error = -ENODEV; | ||
131 | |||
132 | if (!ibmebusdrv->probe) | ||
133 | return error; | ||
134 | |||
135 | id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev); | ||
136 | if (id) { | ||
137 | error = ibmebusdrv->probe(ibmebusdev, id); | ||
138 | } | ||
139 | |||
140 | return error; | ||
141 | } | ||
142 | |||
143 | static int ibmebus_bus_remove(struct device *dev) | ||
144 | { | ||
145 | struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev); | ||
146 | struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver); | ||
147 | |||
148 | if (ibmebusdrv->remove) { | ||
149 | return ibmebusdrv->remove(ibmebusdev); | ||
150 | } | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void __devinit ibmebus_dev_release(struct device *dev) | ||
156 | { | ||
157 | of_node_put(to_ibmebus_dev(dev)->ofdev.node); | ||
158 | kfree(to_ibmebus_dev(dev)); | ||
159 | } | ||
160 | |||
161 | static ssize_t ibmebusdev_show_name(struct device *dev, | ||
162 | struct device_attribute *attr, char *buf) | ||
163 | { | ||
164 | return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name); | ||
165 | } | ||
166 | static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name, | ||
167 | NULL); | ||
168 | |||
169 | static struct ibmebus_dev* __devinit ibmebus_register_device_common( | ||
170 | struct ibmebus_dev *dev, char *name) | ||
171 | { | ||
172 | int err = 0; | ||
173 | |||
174 | dev->name = name; | ||
175 | dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev; | ||
176 | dev->ofdev.dev.bus = &ibmebus_bus_type; | ||
177 | dev->ofdev.dev.release = ibmebus_dev_release; | ||
178 | |||
179 | /* An ibmebusdev is based on a of_device. We have to change the | ||
180 | * bus type to use our own DMA mapping operations. | ||
181 | */ | ||
182 | if ((err = of_device_register(&dev->ofdev)) != 0) { | ||
183 | printk(KERN_ERR "%s: failed to register device (%d).\n", | ||
184 | __FUNCTION__, err); | ||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | device_create_file(&dev->ofdev.dev, &dev_attr_name); | ||
189 | |||
190 | return dev; | ||
191 | } | ||
192 | |||
193 | static struct ibmebus_dev* __devinit ibmebus_register_device_node( | ||
194 | struct device_node *dn) | ||
195 | { | ||
196 | struct ibmebus_dev *dev; | ||
197 | char *loc_code; | ||
198 | int length; | ||
199 | |||
200 | loc_code = (char *)get_property(dn, "ibm,loc-code", NULL); | ||
201 | if (!loc_code) { | ||
202 | printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n", | ||
203 | __FUNCTION__, dn->name ? dn->name : "<unknown>"); | ||
204 | return NULL; | ||
205 | } | ||
206 | |||
207 | if (strlen(loc_code) == 0) { | ||
208 | printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n", | ||
209 | __FUNCTION__); | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | dev = kmalloc(sizeof(struct ibmebus_dev), GFP_KERNEL); | ||
214 | if (!dev) { | ||
215 | return NULL; | ||
216 | } | ||
217 | memset(dev, 0, sizeof(struct ibmebus_dev)); | ||
218 | |||
219 | dev->ofdev.node = of_node_get(dn); | ||
220 | |||
221 | length = strlen(loc_code); | ||
222 | memcpy(dev->ofdev.dev.bus_id, loc_code | ||
223 | + (length - min(length, BUS_ID_SIZE - 1)), | ||
224 | min(length, BUS_ID_SIZE - 1)); | ||
225 | |||
226 | /* Register with generic device framework. */ | ||
227 | if (ibmebus_register_device_common(dev, dn->name) == NULL) { | ||
228 | kfree(dev); | ||
229 | return NULL; | ||
230 | } | ||
231 | |||
232 | return dev; | ||
233 | } | ||
234 | |||
235 | static void ibmebus_probe_of_nodes(char* name) | ||
236 | { | ||
237 | struct device_node *dn = NULL; | ||
238 | |||
239 | while ((dn = of_find_node_by_name(dn, name))) { | ||
240 | if (ibmebus_register_device_node(dn) == NULL) { | ||
241 | of_node_put(dn); | ||
242 | |||
243 | return; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | of_node_put(dn); | ||
248 | |||
249 | return; | ||
250 | } | ||
251 | |||
252 | static void ibmebus_add_devices_by_id(struct of_device_id *idt) | ||
253 | { | ||
254 | while (strlen(idt->name) > 0) { | ||
255 | ibmebus_probe_of_nodes(idt->name); | ||
256 | idt++; | ||
257 | } | ||
258 | |||
259 | return; | ||
260 | } | ||
261 | |||
262 | static int ibmebus_match_helper(struct device *dev, void *data) | ||
263 | { | ||
264 | if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0) | ||
265 | return 1; | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int ibmebus_unregister_device(struct device *dev) | ||
271 | { | ||
272 | device_remove_file(dev, &dev_attr_name); | ||
273 | of_device_unregister(to_of_device(dev)); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static void ibmebus_remove_devices_by_id(struct of_device_id *idt) | ||
279 | { | ||
280 | struct device *dev; | ||
281 | |||
282 | while (strlen(idt->name) > 0) { | ||
283 | while ((dev = bus_find_device(&ibmebus_bus_type, NULL, | ||
284 | (void*)idt->name, | ||
285 | ibmebus_match_helper))) { | ||
286 | ibmebus_unregister_device(dev); | ||
287 | } | ||
288 | idt++; | ||
289 | |||
290 | } | ||
291 | |||
292 | return; | ||
293 | } | ||
294 | |||
295 | int ibmebus_register_driver(struct ibmebus_driver *drv) | ||
296 | { | ||
297 | int err = 0; | ||
298 | |||
299 | drv->driver.name = drv->name; | ||
300 | drv->driver.bus = &ibmebus_bus_type; | ||
301 | drv->driver.probe = ibmebus_bus_probe; | ||
302 | drv->driver.remove = ibmebus_bus_remove; | ||
303 | |||
304 | if ((err = driver_register(&drv->driver) != 0)) | ||
305 | return err; | ||
306 | |||
307 | ibmebus_add_devices_by_id(drv->id_table); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | EXPORT_SYMBOL(ibmebus_register_driver); | ||
312 | |||
313 | void ibmebus_unregister_driver(struct ibmebus_driver *drv) | ||
314 | { | ||
315 | driver_unregister(&drv->driver); | ||
316 | ibmebus_remove_devices_by_id(drv->id_table); | ||
317 | } | ||
318 | EXPORT_SYMBOL(ibmebus_unregister_driver); | ||
319 | |||
320 | int ibmebus_request_irq(struct ibmebus_dev *dev, | ||
321 | u32 ist, | ||
322 | irqreturn_t (*handler)(int, void*, struct pt_regs *), | ||
323 | unsigned long irq_flags, const char * devname, | ||
324 | void *dev_id) | ||
325 | { | ||
326 | unsigned int irq = virt_irq_create_mapping(ist); | ||
327 | |||
328 | if (irq == NO_IRQ) | ||
329 | return -EINVAL; | ||
330 | |||
331 | irq = irq_offset_up(irq); | ||
332 | |||
333 | return request_irq(irq, handler, | ||
334 | irq_flags, devname, dev_id); | ||
335 | } | ||
336 | EXPORT_SYMBOL(ibmebus_request_irq); | ||
337 | |||
338 | void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id) | ||
339 | { | ||
340 | unsigned int irq = virt_irq_create_mapping(ist); | ||
341 | |||
342 | irq = irq_offset_up(irq); | ||
343 | free_irq(irq, dev_id); | ||
344 | |||
345 | return; | ||
346 | } | ||
347 | EXPORT_SYMBOL(ibmebus_free_irq); | ||
348 | |||
349 | static int ibmebus_bus_match(struct device *dev, struct device_driver *drv) | ||
350 | { | ||
351 | const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev); | ||
352 | struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv); | ||
353 | const struct of_device_id *ids = ebus_drv->id_table; | ||
354 | const struct of_device_id *found_id; | ||
355 | |||
356 | if (!ids) | ||
357 | return 0; | ||
358 | |||
359 | found_id = of_match_device(ids, &ebus_dev->ofdev); | ||
360 | if (found_id) | ||
361 | return 1; | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | struct bus_type ibmebus_bus_type = { | ||
367 | .name = "ibmebus", | ||
368 | .match = ibmebus_bus_match, | ||
369 | }; | ||
370 | EXPORT_SYMBOL(ibmebus_bus_type); | ||
371 | |||
372 | static int __init ibmebus_bus_init(void) | ||
373 | { | ||
374 | int err; | ||
375 | |||
376 | printk(KERN_INFO "IBM eBus Device Driver\n"); | ||
377 | |||
378 | err = bus_register(&ibmebus_bus_type); | ||
379 | if (err) { | ||
380 | printk(KERN_ERR ":%s: failed to register IBM eBus.\n", | ||
381 | __FUNCTION__); | ||
382 | return err; | ||
383 | } | ||
384 | |||
385 | err = device_register(&ibmebus_bus_device.ofdev.dev); | ||
386 | if (err) { | ||
387 | printk(KERN_WARNING "%s: device_register returned %i\n", | ||
388 | __FUNCTION__, err); | ||
389 | bus_unregister(&ibmebus_bus_type); | ||
390 | |||
391 | return err; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | __initcall(ibmebus_bus_init); | ||
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5a71ed9612fe..5651032d8706 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -31,7 +31,6 @@ | |||
31 | * to reduce code space and undefined function references. | 31 | * to reduce code space and undefined function references. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/errno.h> | ||
35 | #include <linux/module.h> | 34 | #include <linux/module.h> |
36 | #include <linux/threads.h> | 35 | #include <linux/threads.h> |
37 | #include <linux/kernel_stat.h> | 36 | #include <linux/kernel_stat.h> |
@@ -44,18 +43,12 @@ | |||
44 | #include <linux/config.h> | 43 | #include <linux/config.h> |
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
47 | #include <linux/pci.h> | ||
48 | #include <linux/delay.h> | 46 | #include <linux/delay.h> |
49 | #include <linux/irq.h> | 47 | #include <linux/irq.h> |
50 | #include <linux/proc_fs.h> | ||
51 | #include <linux/random.h> | ||
52 | #include <linux/seq_file.h> | 48 | #include <linux/seq_file.h> |
53 | #include <linux/cpumask.h> | 49 | #include <linux/cpumask.h> |
54 | #include <linux/profile.h> | 50 | #include <linux/profile.h> |
55 | #include <linux/bitops.h> | 51 | #include <linux/bitops.h> |
56 | #ifdef CONFIG_PPC64 | ||
57 | #include <linux/kallsyms.h> | ||
58 | #endif | ||
59 | 52 | ||
60 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
61 | #include <asm/system.h> | 54 | #include <asm/system.h> |
@@ -66,8 +59,7 @@ | |||
66 | #include <asm/prom.h> | 59 | #include <asm/prom.h> |
67 | #include <asm/ptrace.h> | 60 | #include <asm/ptrace.h> |
68 | #include <asm/machdep.h> | 61 | #include <asm/machdep.h> |
69 | #ifdef CONFIG_PPC64 | 62 | #ifdef CONFIG_PPC_ISERIES |
70 | #include <asm/iseries/it_lp_queue.h> | ||
71 | #include <asm/paca.h> | 63 | #include <asm/paca.h> |
72 | #endif | 64 | #endif |
73 | 65 | ||
@@ -78,10 +70,6 @@ EXPORT_SYMBOL(__irq_offset_value); | |||
78 | 70 | ||
79 | static int ppc_spurious_interrupts; | 71 | static int ppc_spurious_interrupts; |
80 | 72 | ||
81 | #if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP) | ||
82 | extern void iSeries_smp_message_recv(struct pt_regs *); | ||
83 | #endif | ||
84 | |||
85 | #ifdef CONFIG_PPC32 | 73 | #ifdef CONFIG_PPC32 |
86 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | 74 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) |
87 | 75 | ||
@@ -195,49 +183,6 @@ void fixup_irqs(cpumask_t map) | |||
195 | } | 183 | } |
196 | #endif | 184 | #endif |
197 | 185 | ||
198 | #ifdef CONFIG_PPC_ISERIES | ||
199 | void do_IRQ(struct pt_regs *regs) | ||
200 | { | ||
201 | struct paca_struct *lpaca; | ||
202 | |||
203 | irq_enter(); | ||
204 | |||
205 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | ||
206 | /* Debugging check for stack overflow: is there less than 2KB free? */ | ||
207 | { | ||
208 | long sp; | ||
209 | |||
210 | sp = __get_SP() & (THREAD_SIZE-1); | ||
211 | |||
212 | if (unlikely(sp < (sizeof(struct thread_info) + 2048))) { | ||
213 | printk("do_IRQ: stack overflow: %ld\n", | ||
214 | sp - sizeof(struct thread_info)); | ||
215 | dump_stack(); | ||
216 | } | ||
217 | } | ||
218 | #endif | ||
219 | |||
220 | lpaca = get_paca(); | ||
221 | #ifdef CONFIG_SMP | ||
222 | if (lpaca->lppaca.int_dword.fields.ipi_cnt) { | ||
223 | lpaca->lppaca.int_dword.fields.ipi_cnt = 0; | ||
224 | iSeries_smp_message_recv(regs); | ||
225 | } | ||
226 | #endif /* CONFIG_SMP */ | ||
227 | if (hvlpevent_is_pending()) | ||
228 | process_hvlpevents(regs); | ||
229 | |||
230 | irq_exit(); | ||
231 | |||
232 | if (lpaca->lppaca.int_dword.fields.decr_int) { | ||
233 | lpaca->lppaca.int_dword.fields.decr_int = 0; | ||
234 | /* Signal a fake decrementer interrupt */ | ||
235 | timer_interrupt(regs); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | #else /* CONFIG_PPC_ISERIES */ | ||
240 | |||
241 | void do_IRQ(struct pt_regs *regs) | 186 | void do_IRQ(struct pt_regs *regs) |
242 | { | 187 | { |
243 | int irq; | 188 | int irq; |
@@ -286,16 +231,24 @@ void do_IRQ(struct pt_regs *regs) | |||
286 | } else | 231 | } else |
287 | #endif | 232 | #endif |
288 | __do_IRQ(irq, regs); | 233 | __do_IRQ(irq, regs); |
289 | } else | 234 | } else if (irq != -2) |
290 | #ifdef CONFIG_PPC32 | 235 | /* That's not SMP safe ... but who cares ? */ |
291 | if (irq != -2) | 236 | ppc_spurious_interrupts++; |
292 | #endif | 237 | |
293 | /* That's not SMP safe ... but who cares ? */ | ||
294 | ppc_spurious_interrupts++; | ||
295 | irq_exit(); | 238 | irq_exit(); |
296 | } | ||
297 | 239 | ||
298 | #endif /* CONFIG_PPC_ISERIES */ | 240 | #ifdef CONFIG_PPC_ISERIES |
241 | { | ||
242 | struct paca_struct *lpaca = get_paca(); | ||
243 | |||
244 | if (lpaca->lppaca.int_dword.fields.decr_int) { | ||
245 | lpaca->lppaca.int_dword.fields.decr_int = 0; | ||
246 | /* Signal a fake decrementer interrupt */ | ||
247 | timer_interrupt(regs); | ||
248 | } | ||
249 | } | ||
250 | #endif | ||
251 | } | ||
299 | 252 | ||
300 | void __init init_IRQ(void) | 253 | void __init init_IRQ(void) |
301 | { | 254 | { |
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c new file mode 100644 index 000000000000..f970ace208d3 --- /dev/null +++ b/arch/powerpc/kernel/legacy_serial.c | |||
@@ -0,0 +1,557 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/serial.h> | ||
4 | #include <linux/serial_8250.h> | ||
5 | #include <linux/serial_core.h> | ||
6 | #include <linux/console.h> | ||
7 | #include <linux/pci.h> | ||
8 | #include <asm/io.h> | ||
9 | #include <asm/mmu.h> | ||
10 | #include <asm/prom.h> | ||
11 | #include <asm/serial.h> | ||
12 | #include <asm/udbg.h> | ||
13 | #include <asm/pci-bridge.h> | ||
14 | #include <asm/ppc-pci.h> | ||
15 | |||
16 | #undef DEBUG | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | #define DBG(fmt...) do { printk(fmt); } while(0) | ||
20 | #else | ||
21 | #define DBG(fmt...) do { } while(0) | ||
22 | #endif | ||
23 | |||
24 | #define MAX_LEGACY_SERIAL_PORTS 8 | ||
25 | |||
26 | static struct plat_serial8250_port | ||
27 | legacy_serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | ||
28 | static struct legacy_serial_info { | ||
29 | struct device_node *np; | ||
30 | unsigned int speed; | ||
31 | unsigned int clock; | ||
32 | phys_addr_t taddr; | ||
33 | } legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS]; | ||
34 | static unsigned int legacy_serial_count; | ||
35 | static int legacy_serial_console = -1; | ||
36 | |||
37 | static int __init add_legacy_port(struct device_node *np, int want_index, | ||
38 | int iotype, phys_addr_t base, | ||
39 | phys_addr_t taddr, unsigned long irq, | ||
40 | unsigned int flags) | ||
41 | { | ||
42 | u32 *clk, *spd, clock = BASE_BAUD * 16; | ||
43 | int index; | ||
44 | |||
45 | /* get clock freq. if present */ | ||
46 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | ||
47 | if (clk && *clk) | ||
48 | clock = *clk; | ||
49 | |||
50 | /* get default speed if present */ | ||
51 | spd = (u32 *)get_property(np, "current-speed", NULL); | ||
52 | |||
53 | /* If we have a location index, then try to use it */ | ||
54 | if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS) | ||
55 | index = want_index; | ||
56 | else | ||
57 | index = legacy_serial_count; | ||
58 | |||
59 | /* if our index is still out of range, that mean that | ||
60 | * array is full, we could scan for a free slot but that | ||
61 | * make little sense to bother, just skip the port | ||
62 | */ | ||
63 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
64 | return -1; | ||
65 | if (index >= legacy_serial_count) | ||
66 | legacy_serial_count = index + 1; | ||
67 | |||
68 | /* Check if there is a port who already claimed our slot */ | ||
69 | if (legacy_serial_infos[index].np != 0) { | ||
70 | /* if we still have some room, move it, else override */ | ||
71 | if (legacy_serial_count < MAX_LEGACY_SERIAL_PORTS) { | ||
72 | printk(KERN_INFO "Moved legacy port %d -> %d\n", | ||
73 | index, legacy_serial_count); | ||
74 | legacy_serial_ports[legacy_serial_count] = | ||
75 | legacy_serial_ports[index]; | ||
76 | legacy_serial_infos[legacy_serial_count] = | ||
77 | legacy_serial_infos[index]; | ||
78 | legacy_serial_count++; | ||
79 | } else { | ||
80 | printk(KERN_INFO "Replacing legacy port %d\n", index); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | /* Now fill the entry */ | ||
85 | memset(&legacy_serial_ports[index], 0, | ||
86 | sizeof(struct plat_serial8250_port)); | ||
87 | if (iotype == UPIO_PORT) | ||
88 | legacy_serial_ports[index].iobase = base; | ||
89 | else | ||
90 | legacy_serial_ports[index].mapbase = base; | ||
91 | legacy_serial_ports[index].iotype = iotype; | ||
92 | legacy_serial_ports[index].uartclk = clock; | ||
93 | legacy_serial_ports[index].irq = irq; | ||
94 | legacy_serial_ports[index].flags = flags; | ||
95 | legacy_serial_infos[index].taddr = taddr; | ||
96 | legacy_serial_infos[index].np = of_node_get(np); | ||
97 | legacy_serial_infos[index].clock = clock; | ||
98 | legacy_serial_infos[index].speed = spd ? *spd : 0; | ||
99 | |||
100 | printk(KERN_INFO "Found legacy serial port %d for %s\n", | ||
101 | index, np->full_name); | ||
102 | printk(KERN_INFO " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d\n", | ||
103 | (iotype == UPIO_PORT) ? "port" : "mem", | ||
104 | (unsigned long long)base, (unsigned long long)taddr, irq, | ||
105 | legacy_serial_ports[index].uartclk, | ||
106 | legacy_serial_infos[index].speed); | ||
107 | |||
108 | return index; | ||
109 | } | ||
110 | |||
111 | static int __init add_legacy_soc_port(struct device_node *np, | ||
112 | struct device_node *soc_dev) | ||
113 | { | ||
114 | phys_addr_t addr; | ||
115 | u32 *addrp; | ||
116 | unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; | ||
117 | |||
118 | /* We only support ports that have a clock frequency properly | ||
119 | * encoded in the device-tree. | ||
120 | */ | ||
121 | if (get_property(np, "clock-frequency", NULL) == NULL) | ||
122 | return -1; | ||
123 | |||
124 | /* Get the address */ | ||
125 | addrp = of_get_address(soc_dev, 0, NULL, NULL); | ||
126 | if (addrp == NULL) | ||
127 | return -1; | ||
128 | |||
129 | addr = of_translate_address(soc_dev, addrp); | ||
130 | |||
131 | /* Add port, irq will be dealt with later. We passed a translated | ||
132 | * IO port value. It will be fixed up later along with the irq | ||
133 | */ | ||
134 | return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags); | ||
135 | } | ||
136 | |||
137 | #ifdef CONFIG_ISA | ||
138 | static int __init add_legacy_isa_port(struct device_node *np, | ||
139 | struct device_node *isa_brg) | ||
140 | { | ||
141 | u32 *reg; | ||
142 | char *typep; | ||
143 | int index = -1; | ||
144 | phys_addr_t taddr; | ||
145 | |||
146 | /* Get the ISA port number */ | ||
147 | reg = (u32 *)get_property(np, "reg", NULL); | ||
148 | if (reg == NULL) | ||
149 | return -1; | ||
150 | |||
151 | /* Verify it's an IO port, we don't support anything else */ | ||
152 | if (!(reg[0] & 0x00000001)) | ||
153 | return -1; | ||
154 | |||
155 | /* Now look for an "ibm,aix-loc" property that gives us ordering | ||
156 | * if any... | ||
157 | */ | ||
158 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | ||
159 | |||
160 | /* If we have a location index, then use it */ | ||
161 | if (typep && *typep == 'S') | ||
162 | index = simple_strtol(typep+1, NULL, 0) - 1; | ||
163 | |||
164 | /* Translate ISA address */ | ||
165 | taddr = of_translate_address(np, reg); | ||
166 | |||
167 | /* Add port, irq will be dealt with later */ | ||
168 | return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr, NO_IRQ, UPF_BOOT_AUTOCONF); | ||
169 | |||
170 | } | ||
171 | #endif | ||
172 | |||
173 | #ifdef CONFIG_PCI | ||
174 | static int __init add_legacy_pci_port(struct device_node *np, | ||
175 | struct device_node *pci_dev) | ||
176 | { | ||
177 | phys_addr_t addr, base; | ||
178 | u32 *addrp; | ||
179 | unsigned int flags; | ||
180 | int iotype, index = -1, lindex = 0; | ||
181 | |||
182 | /* We only support ports that have a clock frequency properly | ||
183 | * encoded in the device-tree (that is have an fcode). Anything | ||
184 | * else can't be used that early and will be normally probed by | ||
185 | * the generic 8250_pci driver later on. The reason is that 8250 | ||
186 | * compatible UARTs on PCI need all sort of quirks (port offsets | ||
187 | * etc...) that this code doesn't know about | ||
188 | */ | ||
189 | if (get_property(np, "clock-frequency", NULL) == NULL) | ||
190 | return -1; | ||
191 | |||
192 | /* Get the PCI address. Assume BAR 0 */ | ||
193 | addrp = of_get_pci_address(pci_dev, 0, NULL, &flags); | ||
194 | if (addrp == NULL) | ||
195 | return -1; | ||
196 | |||
197 | /* We only support BAR 0 for now */ | ||
198 | iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT; | ||
199 | addr = of_translate_address(pci_dev, addrp); | ||
200 | |||
201 | /* Set the IO base to the same as the translated address for MMIO, | ||
202 | * or to the domain local IO base for PIO (it will be fixed up later) | ||
203 | */ | ||
204 | if (iotype == UPIO_MEM) | ||
205 | base = addr; | ||
206 | else | ||
207 | base = addrp[2]; | ||
208 | |||
209 | /* Try to guess an index... If we have subdevices of the pci dev, | ||
210 | * we get to their "reg" property | ||
211 | */ | ||
212 | if (np != pci_dev) { | ||
213 | u32 *reg = (u32 *)get_property(np, "reg", NULL); | ||
214 | if (reg && (*reg < 4)) | ||
215 | index = lindex = *reg; | ||
216 | } | ||
217 | |||
218 | /* Local index means it's the Nth port in the PCI chip. Unfortunately | ||
219 | * the offset to add here is device specific. We know about those | ||
220 | * EXAR ports and we default to the most common case. If your UART | ||
221 | * doesn't work for these settings, you'll have to add your own special | ||
222 | * cases here | ||
223 | */ | ||
224 | if (device_is_compatible(pci_dev, "pci13a8,152") || | ||
225 | device_is_compatible(pci_dev, "pci13a8,154") || | ||
226 | device_is_compatible(pci_dev, "pci13a8,158")) { | ||
227 | addr += 0x200 * lindex; | ||
228 | base += 0x200 * lindex; | ||
229 | } else { | ||
230 | addr += 8 * lindex; | ||
231 | base += 8 * lindex; | ||
232 | } | ||
233 | |||
234 | /* Add port, irq will be dealt with later. We passed a translated | ||
235 | * IO port value. It will be fixed up later along with the irq | ||
236 | */ | ||
237 | return add_legacy_port(np, index, iotype, base, addr, NO_IRQ, UPF_BOOT_AUTOCONF); | ||
238 | } | ||
239 | #endif | ||
240 | |||
241 | /* | ||
242 | * This is called very early, as part of setup_system() or eventually | ||
243 | * setup_arch(), basically before anything else in this file. This function | ||
244 | * will try to build a list of all the available 8250-compatible serial ports | ||
245 | * in the machine using the Open Firmware device-tree. It currently only deals | ||
246 | * with ISA and PCI busses but could be extended. It allows a very early boot | ||
247 | * console to be initialized, that list is also used later to provide 8250 with | ||
248 | * the machine non-PCI ports and to properly pick the default console port | ||
249 | */ | ||
250 | void __init find_legacy_serial_ports(void) | ||
251 | { | ||
252 | struct device_node *np, *stdout = NULL; | ||
253 | char *path; | ||
254 | int index; | ||
255 | |||
256 | DBG(" -> find_legacy_serial_port()\n"); | ||
257 | |||
258 | /* Now find out if one of these is out firmware console */ | ||
259 | path = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | ||
260 | if (path != NULL) { | ||
261 | stdout = of_find_node_by_path(path); | ||
262 | if (stdout) | ||
263 | DBG("stdout is %s\n", stdout->full_name); | ||
264 | } else { | ||
265 | DBG(" no linux,stdout-path !\n"); | ||
266 | } | ||
267 | |||
268 | /* First fill our array with SOC ports */ | ||
269 | for (np = NULL; (np = of_find_compatible_node(np, "serial", "ns16550")) != NULL;) { | ||
270 | struct device_node *soc = of_get_parent(np); | ||
271 | if (soc && !strcmp(soc->type, "soc")) { | ||
272 | index = add_legacy_soc_port(np, np); | ||
273 | if (index >= 0 && np == stdout) | ||
274 | legacy_serial_console = index; | ||
275 | } | ||
276 | of_node_put(soc); | ||
277 | } | ||
278 | |||
279 | #ifdef CONFIG_ISA | ||
280 | /* First fill our array with ISA ports */ | ||
281 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | ||
282 | struct device_node *isa = of_get_parent(np); | ||
283 | if (isa && !strcmp(isa->name, "isa")) { | ||
284 | index = add_legacy_isa_port(np, isa); | ||
285 | if (index >= 0 && np == stdout) | ||
286 | legacy_serial_console = index; | ||
287 | } | ||
288 | of_node_put(isa); | ||
289 | } | ||
290 | #endif | ||
291 | |||
292 | #ifdef CONFIG_PCI | ||
293 | /* Next, try to locate PCI ports */ | ||
294 | for (np = NULL; (np = of_find_all_nodes(np));) { | ||
295 | struct device_node *pci, *parent = of_get_parent(np); | ||
296 | if (parent && !strcmp(parent->name, "isa")) { | ||
297 | of_node_put(parent); | ||
298 | continue; | ||
299 | } | ||
300 | if (strcmp(np->name, "serial") && strcmp(np->type, "serial")) { | ||
301 | of_node_put(parent); | ||
302 | continue; | ||
303 | } | ||
304 | /* Check for known pciclass, and also check wether we have | ||
305 | * a device with child nodes for ports or not | ||
306 | */ | ||
307 | if (device_is_compatible(np, "pciclass,0700") || | ||
308 | device_is_compatible(np, "pciclass,070002")) | ||
309 | pci = np; | ||
310 | else if (device_is_compatible(parent, "pciclass,0700") || | ||
311 | device_is_compatible(parent, "pciclass,070002")) | ||
312 | pci = parent; | ||
313 | else { | ||
314 | of_node_put(parent); | ||
315 | continue; | ||
316 | } | ||
317 | index = add_legacy_pci_port(np, pci); | ||
318 | if (index >= 0 && np == stdout) | ||
319 | legacy_serial_console = index; | ||
320 | of_node_put(parent); | ||
321 | } | ||
322 | #endif | ||
323 | |||
324 | DBG("legacy_serial_console = %d\n", legacy_serial_console); | ||
325 | |||
326 | /* udbg is 64 bits only for now, that will change soon though ... */ | ||
327 | while (legacy_serial_console >= 0) { | ||
328 | struct legacy_serial_info *info = | ||
329 | &legacy_serial_infos[legacy_serial_console]; | ||
330 | void __iomem *addr; | ||
331 | |||
332 | if (info->taddr == 0) | ||
333 | break; | ||
334 | addr = ioremap(info->taddr, 0x1000); | ||
335 | if (addr == NULL) | ||
336 | break; | ||
337 | if (info->speed == 0) | ||
338 | info->speed = udbg_probe_uart_speed(addr, info->clock); | ||
339 | DBG("default console speed = %d\n", info->speed); | ||
340 | udbg_init_uart(addr, info->speed, info->clock); | ||
341 | break; | ||
342 | } | ||
343 | |||
344 | DBG(" <- find_legacy_serial_port()\n"); | ||
345 | } | ||
346 | |||
347 | static struct platform_device serial_device = { | ||
348 | .name = "serial8250", | ||
349 | .id = PLAT8250_DEV_PLATFORM, | ||
350 | .dev = { | ||
351 | .platform_data = legacy_serial_ports, | ||
352 | }, | ||
353 | }; | ||
354 | |||
355 | static void __init fixup_port_irq(int index, | ||
356 | struct device_node *np, | ||
357 | struct plat_serial8250_port *port) | ||
358 | { | ||
359 | DBG("fixup_port_irq(%d)\n", index); | ||
360 | |||
361 | /* Check for interrupts in that node */ | ||
362 | if (np->n_intrs > 0) { | ||
363 | port->irq = np->intrs[0].line; | ||
364 | DBG(" port %d (%s), irq=%d\n", | ||
365 | index, np->full_name, port->irq); | ||
366 | return; | ||
367 | } | ||
368 | |||
369 | /* Check for interrupts in the parent */ | ||
370 | np = of_get_parent(np); | ||
371 | if (np == NULL) | ||
372 | return; | ||
373 | |||
374 | if (np->n_intrs > 0) { | ||
375 | port->irq = np->intrs[0].line; | ||
376 | DBG(" port %d (%s), irq=%d\n", | ||
377 | index, np->full_name, port->irq); | ||
378 | } | ||
379 | of_node_put(np); | ||
380 | } | ||
381 | |||
382 | static void __init fixup_port_pio(int index, | ||
383 | struct device_node *np, | ||
384 | struct plat_serial8250_port *port) | ||
385 | { | ||
386 | #ifdef CONFIG_PCI | ||
387 | struct pci_controller *hose; | ||
388 | |||
389 | DBG("fixup_port_pio(%d)\n", index); | ||
390 | |||
391 | hose = pci_find_hose_for_OF_device(np); | ||
392 | if (hose) { | ||
393 | unsigned long offset = (unsigned long)hose->io_base_virt - | ||
394 | #ifdef CONFIG_PPC64 | ||
395 | pci_io_base; | ||
396 | #else | ||
397 | isa_io_base; | ||
398 | #endif | ||
399 | DBG("port %d, IO %lx -> %lx\n", | ||
400 | index, port->iobase, port->iobase + offset); | ||
401 | port->iobase += offset; | ||
402 | } | ||
403 | #endif | ||
404 | } | ||
405 | |||
406 | static void __init fixup_port_mmio(int index, | ||
407 | struct device_node *np, | ||
408 | struct plat_serial8250_port *port) | ||
409 | { | ||
410 | DBG("fixup_port_mmio(%d)\n", index); | ||
411 | |||
412 | port->membase = ioremap(port->mapbase, 0x100); | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * This is called as an arch initcall, hopefully before the PCI bus is | ||
417 | * probed and/or the 8250 driver loaded since we need to register our | ||
418 | * platform devices before 8250 PCI ones are detected as some of them | ||
419 | * must properly "override" the platform ones. | ||
420 | * | ||
421 | * This function fixes up the interrupt value for platform ports as it | ||
422 | * couldn't be done earlier before interrupt maps have been parsed. It | ||
423 | * also "corrects" the IO address for PIO ports for the same reason, | ||
424 | * since earlier, the PHBs virtual IO space wasn't assigned yet. It then | ||
425 | * registers all those platform ports for use by the 8250 driver when it | ||
426 | * finally loads. | ||
427 | */ | ||
428 | static int __init serial_dev_init(void) | ||
429 | { | ||
430 | int i; | ||
431 | |||
432 | if (legacy_serial_count == 0) | ||
433 | return -ENODEV; | ||
434 | |||
435 | /* | ||
436 | * Before we register the platfrom serial devices, we need | ||
437 | * to fixup their interrutps and their IO ports. | ||
438 | */ | ||
439 | DBG("Fixing serial ports interrupts and IO ports ...\n"); | ||
440 | |||
441 | for (i = 0; i < legacy_serial_count; i++) { | ||
442 | struct plat_serial8250_port *port = &legacy_serial_ports[i]; | ||
443 | struct device_node *np = legacy_serial_infos[i].np; | ||
444 | |||
445 | if (port->irq == NO_IRQ) | ||
446 | fixup_port_irq(i, np, port); | ||
447 | if (port->iotype == UPIO_PORT) | ||
448 | fixup_port_pio(i, np, port); | ||
449 | if (port->iotype == UPIO_MEM) | ||
450 | fixup_port_mmio(i, np, port); | ||
451 | } | ||
452 | |||
453 | DBG("Registering platform serial ports\n"); | ||
454 | |||
455 | return platform_device_register(&serial_device); | ||
456 | } | ||
457 | arch_initcall(serial_dev_init); | ||
458 | |||
459 | |||
460 | /* | ||
461 | * This is called very early, as part of console_init() (typically just after | ||
462 | * time_init()). This function is respondible for trying to find a good | ||
463 | * default console on serial ports. It tries to match the open firmware | ||
464 | * default output with one of the available serial console drivers, either | ||
465 | * one of the platform serial ports that have been probed earlier by | ||
466 | * find_legacy_serial_ports() or some more platform specific ones. | ||
467 | */ | ||
468 | static int __init check_legacy_serial_console(void) | ||
469 | { | ||
470 | struct device_node *prom_stdout = NULL; | ||
471 | int speed = 0, offset = 0; | ||
472 | char *name; | ||
473 | u32 *spd; | ||
474 | |||
475 | DBG(" -> check_legacy_serial_console()\n"); | ||
476 | |||
477 | /* The user has requested a console so this is already set up. */ | ||
478 | if (strstr(saved_command_line, "console=")) { | ||
479 | DBG(" console was specified !\n"); | ||
480 | return -EBUSY; | ||
481 | } | ||
482 | |||
483 | if (!of_chosen) { | ||
484 | DBG(" of_chosen is NULL !\n"); | ||
485 | return -ENODEV; | ||
486 | } | ||
487 | |||
488 | if (legacy_serial_console < 0) { | ||
489 | DBG(" legacy_serial_console not found !\n"); | ||
490 | return -ENODEV; | ||
491 | } | ||
492 | /* We are getting a weird phandle from OF ... */ | ||
493 | /* ... So use the full path instead */ | ||
494 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | ||
495 | if (name == NULL) { | ||
496 | DBG(" no linux,stdout-path !\n"); | ||
497 | return -ENODEV; | ||
498 | } | ||
499 | prom_stdout = of_find_node_by_path(name); | ||
500 | if (!prom_stdout) { | ||
501 | DBG(" can't find stdout package %s !\n", name); | ||
502 | return -ENODEV; | ||
503 | } | ||
504 | DBG("stdout is %s\n", prom_stdout->full_name); | ||
505 | |||
506 | name = (char *)get_property(prom_stdout, "name", NULL); | ||
507 | if (!name) { | ||
508 | DBG(" stdout package has no name !\n"); | ||
509 | goto not_found; | ||
510 | } | ||
511 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); | ||
512 | if (spd) | ||
513 | speed = *spd; | ||
514 | |||
515 | if (0) | ||
516 | ; | ||
517 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
518 | else if (strcmp(name, "serial") == 0) { | ||
519 | int i; | ||
520 | /* Look for it in probed array */ | ||
521 | for (i = 0; i < legacy_serial_count; i++) { | ||
522 | if (prom_stdout != legacy_serial_infos[i].np) | ||
523 | continue; | ||
524 | offset = i; | ||
525 | speed = legacy_serial_infos[i].speed; | ||
526 | break; | ||
527 | } | ||
528 | if (i >= legacy_serial_count) | ||
529 | goto not_found; | ||
530 | } | ||
531 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | ||
532 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | ||
533 | else if (strcmp(name, "ch-a") == 0) | ||
534 | offset = 0; | ||
535 | else if (strcmp(name, "ch-b") == 0) | ||
536 | offset = 1; | ||
537 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | ||
538 | else | ||
539 | goto not_found; | ||
540 | of_node_put(prom_stdout); | ||
541 | |||
542 | DBG("Found serial console at ttyS%d\n", offset); | ||
543 | |||
544 | if (speed) { | ||
545 | static char __initdata opt[16]; | ||
546 | sprintf(opt, "%d", speed); | ||
547 | return add_preferred_console("ttyS", offset, opt); | ||
548 | } else | ||
549 | return add_preferred_console("ttyS", offset, NULL); | ||
550 | |||
551 | not_found: | ||
552 | DBG("No preferred console found !\n"); | ||
553 | of_node_put(prom_stdout); | ||
554 | return -ENODEV; | ||
555 | } | ||
556 | console_initcall(check_legacy_serial_console); | ||
557 | |||
diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c index 5a05a797485f..584d1e3c013d 100644 --- a/arch/powerpc/kernel/lparmap.c +++ b/arch/powerpc/kernel/lparmap.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | #include <asm/mmu.h> | 9 | #include <asm/mmu.h> |
10 | #include <asm/page.h> | 10 | #include <asm/pgtable.h> |
11 | #include <asm/iseries/lpar_map.h> | 11 | #include <asm/iseries/lpar_map.h> |
12 | 12 | ||
13 | const struct LparMap __attribute__((__section__(".text"))) xLparMap = { | 13 | const struct LparMap __attribute__((__section__(".text"))) xLparMap = { |
@@ -16,16 +16,16 @@ const struct LparMap __attribute__((__section__(".text"))) xLparMap = { | |||
16 | .xSegmentTableOffs = STAB0_PAGE, | 16 | .xSegmentTableOffs = STAB0_PAGE, |
17 | 17 | ||
18 | .xEsids = { | 18 | .xEsids = { |
19 | { .xKernelEsid = GET_ESID(KERNELBASE), | 19 | { .xKernelEsid = GET_ESID(PAGE_OFFSET), |
20 | .xKernelVsid = KERNEL_VSID(KERNELBASE), }, | 20 | .xKernelVsid = KERNEL_VSID(PAGE_OFFSET), }, |
21 | { .xKernelEsid = GET_ESID(VMALLOCBASE), | 21 | { .xKernelEsid = GET_ESID(VMALLOC_START), |
22 | .xKernelVsid = KERNEL_VSID(VMALLOCBASE), }, | 22 | .xKernelVsid = KERNEL_VSID(VMALLOC_START), }, |
23 | }, | 23 | }, |
24 | 24 | ||
25 | .xRanges = { | 25 | .xRanges = { |
26 | { .xPages = HvPagesToMap, | 26 | { .xPages = HvPagesToMap, |
27 | .xOffset = 0, | 27 | .xOffset = 0, |
28 | .xVPN = KERNEL_VSID(KERNELBASE) << (SID_SHIFT - HW_PAGE_SHIFT), | 28 | .xVPN = KERNEL_VSID(PAGE_OFFSET) << (SID_SHIFT - HW_PAGE_SHIFT), |
29 | }, | 29 | }, |
30 | }, | 30 | }, |
31 | }; | 31 | }; |
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c new file mode 100644 index 000000000000..a91e40c9ae45 --- /dev/null +++ b/arch/powerpc/kernel/machine_kexec.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Code to handle transition of Linux booting another kernel. | ||
3 | * | ||
4 | * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> | ||
5 | * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz | ||
6 | * Copyright (C) 2005 IBM Corporation. | ||
7 | * | ||
8 | * This source code is licensed under the GNU General Public License, | ||
9 | * Version 2. See the file COPYING for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kexec.h> | ||
13 | #include <linux/reboot.h> | ||
14 | #include <linux/threads.h> | ||
15 | #include <asm/machdep.h> | ||
16 | |||
17 | /* | ||
18 | * Provide a dummy crash_notes definition until crash dump is implemented. | ||
19 | * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. | ||
20 | */ | ||
21 | note_buf_t crash_notes[NR_CPUS]; | ||
22 | |||
23 | void machine_crash_shutdown(struct pt_regs *regs) | ||
24 | { | ||
25 | if (ppc_md.machine_crash_shutdown) | ||
26 | ppc_md.machine_crash_shutdown(regs); | ||
27 | } | ||
28 | |||
29 | /* | ||
30 | * Do what every setup is needed on image and the | ||
31 | * reboot code buffer to allow us to avoid allocations | ||
32 | * later. | ||
33 | */ | ||
34 | int machine_kexec_prepare(struct kimage *image) | ||
35 | { | ||
36 | if (ppc_md.machine_kexec_prepare) | ||
37 | return ppc_md.machine_kexec_prepare(image); | ||
38 | /* | ||
39 | * Fail if platform doesn't provide its own machine_kexec_prepare | ||
40 | * implementation. | ||
41 | */ | ||
42 | return -ENOSYS; | ||
43 | } | ||
44 | |||
45 | void machine_kexec_cleanup(struct kimage *image) | ||
46 | { | ||
47 | if (ppc_md.machine_kexec_cleanup) | ||
48 | ppc_md.machine_kexec_cleanup(image); | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Do not allocate memory (or fail in any way) in machine_kexec(). | ||
53 | * We are past the point of no return, committed to rebooting now. | ||
54 | */ | ||
55 | NORET_TYPE void machine_kexec(struct kimage *image) | ||
56 | { | ||
57 | if (ppc_md.machine_kexec) | ||
58 | ppc_md.machine_kexec(image); | ||
59 | else { | ||
60 | /* | ||
61 | * Fall back to normal restart if platform doesn't provide | ||
62 | * its own kexec function, and user insist to kexec... | ||
63 | */ | ||
64 | machine_restart(NULL); | ||
65 | } | ||
66 | for(;;); | ||
67 | } | ||
diff --git a/arch/powerpc/kernel/machine_kexec_32.c b/arch/powerpc/kernel/machine_kexec_32.c new file mode 100644 index 000000000000..443606134dff --- /dev/null +++ b/arch/powerpc/kernel/machine_kexec_32.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * PPC32 code to handle Linux booting another kernel. | ||
3 | * | ||
4 | * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> | ||
5 | * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz | ||
6 | * Copyright (C) 2005 IBM Corporation. | ||
7 | * | ||
8 | * This source code is licensed under the GNU General Public License, | ||
9 | * Version 2. See the file COPYING for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kexec.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <asm/cacheflush.h> | ||
16 | #include <asm/hw_irq.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | typedef NORET_TYPE void (*relocate_new_kernel_t)( | ||
20 | unsigned long indirection_page, | ||
21 | unsigned long reboot_code_buffer, | ||
22 | unsigned long start_address) ATTRIB_NORET; | ||
23 | |||
24 | /* | ||
25 | * This is a generic machine_kexec function suitable at least for | ||
26 | * non-OpenFirmware embedded platforms. | ||
27 | * It merely copies the image relocation code to the control page and | ||
28 | * jumps to it. | ||
29 | * A platform specific function may just call this one. | ||
30 | */ | ||
31 | void default_machine_kexec(struct kimage *image) | ||
32 | { | ||
33 | const extern unsigned char relocate_new_kernel[]; | ||
34 | const extern unsigned int relocate_new_kernel_size; | ||
35 | unsigned long page_list; | ||
36 | unsigned long reboot_code_buffer, reboot_code_buffer_phys; | ||
37 | relocate_new_kernel_t rnk; | ||
38 | |||
39 | /* Interrupts aren't acceptable while we reboot */ | ||
40 | local_irq_disable(); | ||
41 | |||
42 | page_list = image->head; | ||
43 | |||
44 | /* we need both effective and real address here */ | ||
45 | reboot_code_buffer = | ||
46 | (unsigned long)page_address(image->control_code_page); | ||
47 | reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); | ||
48 | |||
49 | /* copy our kernel relocation code to the control code page */ | ||
50 | memcpy((void *)reboot_code_buffer, relocate_new_kernel, | ||
51 | relocate_new_kernel_size); | ||
52 | |||
53 | flush_icache_range(reboot_code_buffer, | ||
54 | reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); | ||
55 | printk(KERN_INFO "Bye!\n"); | ||
56 | |||
57 | /* now call it */ | ||
58 | rnk = (relocate_new_kernel_t) reboot_code_buffer; | ||
59 | (*rnk)(page_list, reboot_code_buffer_phys, image->start); | ||
60 | } | ||
61 | |||
62 | int default_machine_kexec_prepare(struct kimage *image) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 97c51e452be7..d6431440c54f 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * machine_kexec.c - handle transition of Linux booting another kernel | 2 | * PPC64 code to handle Linux booting another kernel. |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2005, IBM Corp. | 4 | * Copyright (C) 2004-2005, IBM Corp. |
5 | * | 5 | * |
@@ -28,21 +28,7 @@ | |||
28 | 28 | ||
29 | #define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ | 29 | #define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ |
30 | 30 | ||
31 | /* Have this around till we move it into crash specific file */ | 31 | int default_machine_kexec_prepare(struct kimage *image) |
32 | note_buf_t crash_notes[NR_CPUS]; | ||
33 | |||
34 | /* Dummy for now. Not sure if we need to have a crash shutdown in here | ||
35 | * and if what it will achieve. Letting it be now to compile the code | ||
36 | * in generic kexec environment | ||
37 | */ | ||
38 | void machine_crash_shutdown(struct pt_regs *regs) | ||
39 | { | ||
40 | /* do nothing right now */ | ||
41 | /* smp_relase_cpus() if we want smp on panic kernel */ | ||
42 | /* cpu_irq_down to isolate us until we are ready */ | ||
43 | } | ||
44 | |||
45 | int machine_kexec_prepare(struct kimage *image) | ||
46 | { | 32 | { |
47 | int i; | 33 | int i; |
48 | unsigned long begin, end; /* limits of segment */ | 34 | unsigned long begin, end; /* limits of segment */ |
@@ -111,11 +97,6 @@ int machine_kexec_prepare(struct kimage *image) | |||
111 | return 0; | 97 | return 0; |
112 | } | 98 | } |
113 | 99 | ||
114 | void machine_kexec_cleanup(struct kimage *image) | ||
115 | { | ||
116 | /* we do nothing in prepare that needs to be undone */ | ||
117 | } | ||
118 | |||
119 | #define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) | 100 | #define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) |
120 | 101 | ||
121 | static void copy_segments(unsigned long ind) | 102 | static void copy_segments(unsigned long ind) |
@@ -172,9 +153,8 @@ void kexec_copy_flush(struct kimage *image) | |||
172 | * including ones that were in place on the original copy | 153 | * including ones that were in place on the original copy |
173 | */ | 154 | */ |
174 | for (i = 0; i < nr_segments; i++) | 155 | for (i = 0; i < nr_segments; i++) |
175 | flush_icache_range(ranges[i].mem + KERNELBASE, | 156 | flush_icache_range((unsigned long)__va(ranges[i].mem), |
176 | ranges[i].mem + KERNELBASE + | 157 | (unsigned long)__va(ranges[i].mem + ranges[i].memsz)); |
177 | ranges[i].memsz); | ||
178 | } | 158 | } |
179 | 159 | ||
180 | #ifdef CONFIG_SMP | 160 | #ifdef CONFIG_SMP |
@@ -283,13 +263,20 @@ extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start, | |||
283 | void (*clear_all)(void)) ATTRIB_NORET; | 263 | void (*clear_all)(void)) ATTRIB_NORET; |
284 | 264 | ||
285 | /* too late to fail here */ | 265 | /* too late to fail here */ |
286 | void machine_kexec(struct kimage *image) | 266 | void default_machine_kexec(struct kimage *image) |
287 | { | 267 | { |
288 | |||
289 | /* prepare control code if any */ | 268 | /* prepare control code if any */ |
290 | 269 | ||
291 | /* shutdown other cpus into our wait loop and quiesce interrupts */ | 270 | /* |
292 | kexec_prepare_cpus(); | 271 | * If the kexec boot is the normal one, need to shutdown other cpus |
272 | * into our wait loop and quiesce interrupts. | ||
273 | * Otherwise, in the case of crashed mode (crashing_cpu >= 0), | ||
274 | * stopping other CPUs and collecting their pt_regs is done before | ||
275 | * using debugger IPI. | ||
276 | */ | ||
277 | |||
278 | if (crashing_cpu == -1) | ||
279 | kexec_prepare_cpus(); | ||
293 | 280 | ||
294 | /* switch to a staticly allocated stack. Based on irq stack code. | 281 | /* switch to a staticly allocated stack. Based on irq stack code. |
295 | * XXX: the task struct will likely be invalid once we do the copy! | 282 | * XXX: the task struct will likely be invalid once we do the copy! |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 624a983a9676..01d0d97a16e1 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -5,6 +5,10 @@ | |||
5 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) | 5 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) |
6 | * and Paul Mackerras. | 6 | * and Paul Mackerras. |
7 | * | 7 | * |
8 | * kexec bits: | ||
9 | * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> | ||
10 | * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz | ||
11 | * | ||
8 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
10 | * as published by the Free Software Foundation; either version | 14 | * as published by the Free Software Foundation; either version |
@@ -24,6 +28,8 @@ | |||
24 | #include <asm/ppc_asm.h> | 28 | #include <asm/ppc_asm.h> |
25 | #include <asm/thread_info.h> | 29 | #include <asm/thread_info.h> |
26 | #include <asm/asm-offsets.h> | 30 | #include <asm/asm-offsets.h> |
31 | #include <asm/processor.h> | ||
32 | #include <asm/kexec.h> | ||
27 | 33 | ||
28 | .text | 34 | .text |
29 | 35 | ||
@@ -1006,3 +1012,110 @@ _GLOBAL(execve) | |||
1006 | */ | 1012 | */ |
1007 | _GLOBAL(__main) | 1013 | _GLOBAL(__main) |
1008 | blr | 1014 | blr |
1015 | |||
1016 | #ifdef CONFIG_KEXEC | ||
1017 | /* | ||
1018 | * Must be relocatable PIC code callable as a C function. | ||
1019 | */ | ||
1020 | .globl relocate_new_kernel | ||
1021 | relocate_new_kernel: | ||
1022 | /* r3 = page_list */ | ||
1023 | /* r4 = reboot_code_buffer */ | ||
1024 | /* r5 = start_address */ | ||
1025 | |||
1026 | li r0, 0 | ||
1027 | |||
1028 | /* | ||
1029 | * Set Machine Status Register to a known status, | ||
1030 | * switch the MMU off and jump to 1: in a single step. | ||
1031 | */ | ||
1032 | |||
1033 | mr r8, r0 | ||
1034 | ori r8, r8, MSR_RI|MSR_ME | ||
1035 | mtspr SPRN_SRR1, r8 | ||
1036 | addi r8, r4, 1f - relocate_new_kernel | ||
1037 | mtspr SPRN_SRR0, r8 | ||
1038 | sync | ||
1039 | rfi | ||
1040 | |||
1041 | 1: | ||
1042 | /* from this point address translation is turned off */ | ||
1043 | /* and interrupts are disabled */ | ||
1044 | |||
1045 | /* set a new stack at the bottom of our page... */ | ||
1046 | /* (not really needed now) */ | ||
1047 | addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ | ||
1048 | stw r0, 0(r1) | ||
1049 | |||
1050 | /* Do the copies */ | ||
1051 | li r6, 0 /* checksum */ | ||
1052 | mr r0, r3 | ||
1053 | b 1f | ||
1054 | |||
1055 | 0: /* top, read another word for the indirection page */ | ||
1056 | lwzu r0, 4(r3) | ||
1057 | |||
1058 | 1: | ||
1059 | /* is it a destination page? (r8) */ | ||
1060 | rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ | ||
1061 | beq 2f | ||
1062 | |||
1063 | rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ | ||
1064 | b 0b | ||
1065 | |||
1066 | 2: /* is it an indirection page? (r3) */ | ||
1067 | rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ | ||
1068 | beq 2f | ||
1069 | |||
1070 | rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ | ||
1071 | subi r3, r3, 4 | ||
1072 | b 0b | ||
1073 | |||
1074 | 2: /* are we done? */ | ||
1075 | rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ | ||
1076 | beq 2f | ||
1077 | b 3f | ||
1078 | |||
1079 | 2: /* is it a source page? (r9) */ | ||
1080 | rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ | ||
1081 | beq 0b | ||
1082 | |||
1083 | rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ | ||
1084 | |||
1085 | li r7, PAGE_SIZE / 4 | ||
1086 | mtctr r7 | ||
1087 | subi r9, r9, 4 | ||
1088 | subi r8, r8, 4 | ||
1089 | 9: | ||
1090 | lwzu r0, 4(r9) /* do the copy */ | ||
1091 | xor r6, r6, r0 | ||
1092 | stwu r0, 4(r8) | ||
1093 | dcbst 0, r8 | ||
1094 | sync | ||
1095 | icbi 0, r8 | ||
1096 | bdnz 9b | ||
1097 | |||
1098 | addi r9, r9, 4 | ||
1099 | addi r8, r8, 4 | ||
1100 | b 0b | ||
1101 | |||
1102 | 3: | ||
1103 | |||
1104 | /* To be certain of avoiding problems with self-modifying code | ||
1105 | * execute a serializing instruction here. | ||
1106 | */ | ||
1107 | isync | ||
1108 | sync | ||
1109 | |||
1110 | /* jump to the entry point, usually the setup routine */ | ||
1111 | mtlr r5 | ||
1112 | blrl | ||
1113 | |||
1114 | 1: b 1b | ||
1115 | |||
1116 | relocate_new_kernel_end: | ||
1117 | |||
1118 | .globl relocate_new_kernel_size | ||
1119 | relocate_new_kernel_size: | ||
1120 | .long relocate_new_kernel_end - relocate_new_kernel | ||
1121 | #endif | ||
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index c0fcd29918ce..fd7db8d542db 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
@@ -80,80 +80,74 @@ static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) | |||
80 | static ssize_t dev_nvram_read(struct file *file, char __user *buf, | 80 | static ssize_t dev_nvram_read(struct file *file, char __user *buf, |
81 | size_t count, loff_t *ppos) | 81 | size_t count, loff_t *ppos) |
82 | { | 82 | { |
83 | ssize_t len; | 83 | ssize_t ret; |
84 | char *tmp_buffer; | 84 | char *tmp = NULL; |
85 | int size; | 85 | ssize_t size; |
86 | 86 | ||
87 | if (ppc_md.nvram_size == NULL) | 87 | ret = -ENODEV; |
88 | return -ENODEV; | 88 | if (!ppc_md.nvram_size) |
89 | goto out; | ||
90 | |||
91 | ret = 0; | ||
89 | size = ppc_md.nvram_size(); | 92 | size = ppc_md.nvram_size(); |
93 | if (*ppos >= size || size < 0) | ||
94 | goto out; | ||
90 | 95 | ||
91 | if (!access_ok(VERIFY_WRITE, buf, count)) | 96 | count = min_t(size_t, count, size - *ppos); |
92 | return -EFAULT; | 97 | count = min(count, PAGE_SIZE); |
93 | if (*ppos >= size) | ||
94 | return 0; | ||
95 | if (count > size) | ||
96 | count = size; | ||
97 | 98 | ||
98 | tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); | 99 | ret = -ENOMEM; |
99 | if (!tmp_buffer) { | 100 | tmp = kmalloc(count, GFP_KERNEL); |
100 | printk(KERN_ERR "dev_read_nvram: kmalloc failed\n"); | 101 | if (!tmp) |
101 | return -ENOMEM; | 102 | goto out; |
102 | } | ||
103 | 103 | ||
104 | len = ppc_md.nvram_read(tmp_buffer, count, ppos); | 104 | ret = ppc_md.nvram_read(tmp, count, ppos); |
105 | if ((long)len <= 0) { | 105 | if (ret <= 0) |
106 | kfree(tmp_buffer); | 106 | goto out; |
107 | return len; | ||
108 | } | ||
109 | 107 | ||
110 | if (copy_to_user(buf, tmp_buffer, len)) { | 108 | if (copy_to_user(buf, tmp, ret)) |
111 | kfree(tmp_buffer); | 109 | ret = -EFAULT; |
112 | return -EFAULT; | ||
113 | } | ||
114 | 110 | ||
115 | kfree(tmp_buffer); | 111 | out: |
116 | return len; | 112 | kfree(tmp); |
113 | return ret; | ||
117 | 114 | ||
118 | } | 115 | } |
119 | 116 | ||
120 | static ssize_t dev_nvram_write(struct file *file, const char __user *buf, | 117 | static ssize_t dev_nvram_write(struct file *file, const char __user *buf, |
121 | size_t count, loff_t *ppos) | 118 | size_t count, loff_t *ppos) |
122 | { | 119 | { |
123 | ssize_t len; | 120 | ssize_t ret; |
124 | char * tmp_buffer; | 121 | char *tmp = NULL; |
125 | int size; | 122 | ssize_t size; |
126 | 123 | ||
127 | if (ppc_md.nvram_size == NULL) | 124 | ret = -ENODEV; |
128 | return -ENODEV; | 125 | if (!ppc_md.nvram_size) |
126 | goto out; | ||
127 | |||
128 | ret = 0; | ||
129 | size = ppc_md.nvram_size(); | 129 | size = ppc_md.nvram_size(); |
130 | if (*ppos >= size || size < 0) | ||
131 | goto out; | ||
130 | 132 | ||
131 | if (!access_ok(VERIFY_READ, buf, count)) | 133 | count = min_t(size_t, count, size - *ppos); |
132 | return -EFAULT; | 134 | count = min(count, PAGE_SIZE); |
133 | if (*ppos >= size) | ||
134 | return 0; | ||
135 | if (count > size) | ||
136 | count = size; | ||
137 | 135 | ||
138 | tmp_buffer = (char *) kmalloc(count, GFP_KERNEL); | 136 | ret = -ENOMEM; |
139 | if (!tmp_buffer) { | 137 | tmp = kmalloc(count, GFP_KERNEL); |
140 | printk(KERN_ERR "dev_nvram_write: kmalloc failed\n"); | 138 | if (!tmp) |
141 | return -ENOMEM; | 139 | goto out; |
142 | } | ||
143 | |||
144 | if (copy_from_user(tmp_buffer, buf, count)) { | ||
145 | kfree(tmp_buffer); | ||
146 | return -EFAULT; | ||
147 | } | ||
148 | 140 | ||
149 | len = ppc_md.nvram_write(tmp_buffer, count, ppos); | 141 | ret = -EFAULT; |
150 | if ((long)len <= 0) { | 142 | if (copy_from_user(tmp, buf, count)) |
151 | kfree(tmp_buffer); | 143 | goto out; |
152 | return len; | 144 | |
153 | } | 145 | ret = ppc_md.nvram_write(tmp, count, ppos); |
146 | |||
147 | out: | ||
148 | kfree(tmp); | ||
149 | return ret; | ||
154 | 150 | ||
155 | kfree(tmp_buffer); | ||
156 | return len; | ||
157 | } | 151 | } |
158 | 152 | ||
159 | static int dev_nvram_ioctl(struct inode *inode, struct file *file, | 153 | static int dev_nvram_ioctl(struct inode *inode, struct file *file, |
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index a7b68f911eb1..999bdd816769 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/page.h> | 17 | #include <asm/page.h> |
18 | #include <asm/lppaca.h> | 18 | #include <asm/lppaca.h> |
19 | #include <asm/iseries/it_lp_queue.h> | 19 | #include <asm/iseries/it_lp_queue.h> |
20 | #include <asm/iseries/it_lp_reg_save.h> | ||
20 | #include <asm/paca.h> | 21 | #include <asm/paca.h> |
21 | 22 | ||
22 | 23 | ||
@@ -26,8 +27,7 @@ extern unsigned long __toc_start; | |||
26 | 27 | ||
27 | /* The Paca is an array with one entry per processor. Each contains an | 28 | /* The Paca is an array with one entry per processor. Each contains an |
28 | * lppaca, which contains the information shared between the | 29 | * lppaca, which contains the information shared between the |
29 | * hypervisor and Linux. Each also contains an ItLpRegSave area which | 30 | * hypervisor and Linux. |
30 | * is used by the hypervisor to save registers. | ||
31 | * On systems with hardware multi-threading, there are two threads | 31 | * On systems with hardware multi-threading, there are two threads |
32 | * per processor. The Paca array must contain an entry for each thread. | 32 | * per processor. The Paca array must contain an entry for each thread. |
33 | * The VPD Areas will give a max logical processors = 2 * max physical | 33 | * The VPD Areas will give a max logical processors = 2 * max physical |
@@ -37,7 +37,6 @@ extern unsigned long __toc_start; | |||
37 | #define PACA_INIT_COMMON(number, start, asrr, asrv) \ | 37 | #define PACA_INIT_COMMON(number, start, asrr, asrv) \ |
38 | .lock_token = 0x8000, \ | 38 | .lock_token = 0x8000, \ |
39 | .paca_index = (number), /* Paca Index */ \ | 39 | .paca_index = (number), /* Paca Index */ \ |
40 | .default_decr = 0x00ff0000, /* Initial Decr */ \ | ||
41 | .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ | 40 | .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ |
42 | .stab_real = (asrr), /* Real pointer to segment table */ \ | 41 | .stab_real = (asrr), /* Real pointer to segment table */ \ |
43 | .stab_addr = (asrv), /* Virt pointer to segment table */ \ | 42 | .stab_addr = (asrv), /* Virt pointer to segment table */ \ |
@@ -57,11 +56,7 @@ extern unsigned long __toc_start; | |||
57 | #ifdef CONFIG_PPC_ISERIES | 56 | #ifdef CONFIG_PPC_ISERIES |
58 | #define PACA_INIT_ISERIES(number) \ | 57 | #define PACA_INIT_ISERIES(number) \ |
59 | .lppaca_ptr = &paca[number].lppaca, \ | 58 | .lppaca_ptr = &paca[number].lppaca, \ |
60 | .reg_save_ptr = &paca[number].reg_save, \ | 59 | .reg_save_ptr = &iseries_reg_save[number], |
61 | .reg_save = { \ | ||
62 | .xDesc = 0xd397d9e2, /* "LpRS" */ \ | ||
63 | .xSize = sizeof(struct ItLpRegSave) \ | ||
64 | } | ||
65 | 60 | ||
66 | #define PACA_INIT(number) \ | 61 | #define PACA_INIT(number) \ |
67 | { \ | 62 | { \ |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 8b6008ab217d..fc60a773af7d 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #ifdef DEBUG | 35 | #ifdef DEBUG |
36 | #include <asm/udbg.h> | 36 | #include <asm/udbg.h> |
37 | #define DBG(fmt...) udbg_printf(fmt) | 37 | #define DBG(fmt...) printk(fmt) |
38 | #else | 38 | #else |
39 | #define DBG(fmt...) | 39 | #define DBG(fmt...) |
40 | #endif | 40 | #endif |
@@ -251,7 +251,7 @@ void pcibios_free_controller(struct pci_controller *phb) | |||
251 | kfree(phb); | 251 | kfree(phb); |
252 | } | 252 | } |
253 | 253 | ||
254 | static void __init pcibios_claim_one_bus(struct pci_bus *b) | 254 | void __devinit pcibios_claim_one_bus(struct pci_bus *b) |
255 | { | 255 | { |
256 | struct pci_dev *dev; | 256 | struct pci_dev *dev; |
257 | struct pci_bus *child_bus; | 257 | struct pci_bus *child_bus; |
@@ -323,6 +323,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) | |||
323 | addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); | 323 | addrs = (u32 *) get_property(node, "assigned-addresses", &proplen); |
324 | if (!addrs) | 324 | if (!addrs) |
325 | return; | 325 | return; |
326 | DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs); | ||
326 | for (; proplen >= 20; proplen -= 20, addrs += 5) { | 327 | for (; proplen >= 20; proplen -= 20, addrs += 5) { |
327 | flags = pci_parse_of_flags(addrs[0]); | 328 | flags = pci_parse_of_flags(addrs[0]); |
328 | if (!flags) | 329 | if (!flags) |
@@ -332,6 +333,9 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) | |||
332 | if (!size) | 333 | if (!size) |
333 | continue; | 334 | continue; |
334 | i = addrs[0] & 0xff; | 335 | i = addrs[0] & 0xff; |
336 | DBG(" base: %llx, size: %llx, i: %x\n", | ||
337 | (unsigned long long)base, (unsigned long long)size, i); | ||
338 | |||
335 | if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { | 339 | if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { |
336 | res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; | 340 | res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; |
337 | } else if (i == dev->rom_base_reg) { | 341 | } else if (i == dev->rom_base_reg) { |
@@ -362,6 +366,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
362 | if (type == NULL) | 366 | if (type == NULL) |
363 | type = ""; | 367 | type = ""; |
364 | 368 | ||
369 | DBG(" create device, devfn: %x, type: %s\n", devfn, type); | ||
370 | |||
365 | memset(dev, 0, sizeof(struct pci_dev)); | 371 | memset(dev, 0, sizeof(struct pci_dev)); |
366 | dev->bus = bus; | 372 | dev->bus = bus; |
367 | dev->sysdata = node; | 373 | dev->sysdata = node; |
@@ -381,6 +387,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
381 | dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); | 387 | dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); |
382 | dev->class = get_int_prop(node, "class-code", 0); | 388 | dev->class = get_int_prop(node, "class-code", 0); |
383 | 389 | ||
390 | DBG(" class: 0x%x\n", dev->class); | ||
391 | |||
384 | dev->current_state = 4; /* unknown power state */ | 392 | dev->current_state = 4; /* unknown power state */ |
385 | 393 | ||
386 | if (!strcmp(type, "pci")) { | 394 | if (!strcmp(type, "pci")) { |
@@ -402,6 +410,8 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
402 | 410 | ||
403 | pci_parse_of_addrs(node, dev); | 411 | pci_parse_of_addrs(node, dev); |
404 | 412 | ||
413 | DBG(" adding to system ...\n"); | ||
414 | |||
405 | pci_device_add(dev, bus); | 415 | pci_device_add(dev, bus); |
406 | 416 | ||
407 | /* XXX pci_scan_msi_device(dev); */ | 417 | /* XXX pci_scan_msi_device(dev); */ |
@@ -418,15 +428,21 @@ void __devinit of_scan_bus(struct device_node *node, | |||
418 | int reglen, devfn; | 428 | int reglen, devfn; |
419 | struct pci_dev *dev; | 429 | struct pci_dev *dev; |
420 | 430 | ||
431 | DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); | ||
432 | |||
421 | while ((child = of_get_next_child(node, child)) != NULL) { | 433 | while ((child = of_get_next_child(node, child)) != NULL) { |
434 | DBG(" * %s\n", child->full_name); | ||
422 | reg = (u32 *) get_property(child, "reg", ®len); | 435 | reg = (u32 *) get_property(child, "reg", ®len); |
423 | if (reg == NULL || reglen < 20) | 436 | if (reg == NULL || reglen < 20) |
424 | continue; | 437 | continue; |
425 | devfn = (reg[0] >> 8) & 0xff; | 438 | devfn = (reg[0] >> 8) & 0xff; |
439 | |||
426 | /* create a new pci_dev for this device */ | 440 | /* create a new pci_dev for this device */ |
427 | dev = of_create_pci_dev(child, bus, devfn); | 441 | dev = of_create_pci_dev(child, bus, devfn); |
428 | if (!dev) | 442 | if (!dev) |
429 | continue; | 443 | continue; |
444 | DBG("dev header type: %x\n", dev->hdr_type); | ||
445 | |||
430 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || | 446 | if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || |
431 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) | 447 | dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) |
432 | of_scan_pci_bridge(child, dev); | 448 | of_scan_pci_bridge(child, dev); |
@@ -446,16 +462,18 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
446 | unsigned int flags; | 462 | unsigned int flags; |
447 | u64 size; | 463 | u64 size; |
448 | 464 | ||
465 | DBG("of_scan_pci_bridge(%s)\n", node->full_name); | ||
466 | |||
449 | /* parse bus-range property */ | 467 | /* parse bus-range property */ |
450 | busrange = (u32 *) get_property(node, "bus-range", &len); | 468 | busrange = (u32 *) get_property(node, "bus-range", &len); |
451 | if (busrange == NULL || len != 8) { | 469 | if (busrange == NULL || len != 8) { |
452 | printk(KERN_ERR "Can't get bus-range for PCI-PCI bridge %s\n", | 470 | printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n", |
453 | node->full_name); | 471 | node->full_name); |
454 | return; | 472 | return; |
455 | } | 473 | } |
456 | ranges = (u32 *) get_property(node, "ranges", &len); | 474 | ranges = (u32 *) get_property(node, "ranges", &len); |
457 | if (ranges == NULL) { | 475 | if (ranges == NULL) { |
458 | printk(KERN_ERR "Can't get ranges for PCI-PCI bridge %s\n", | 476 | printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", |
459 | node->full_name); | 477 | node->full_name); |
460 | return; | 478 | return; |
461 | } | 479 | } |
@@ -509,10 +527,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
509 | } | 527 | } |
510 | sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), | 528 | sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), |
511 | bus->number); | 529 | bus->number); |
530 | DBG(" bus name: %s\n", bus->name); | ||
512 | 531 | ||
513 | mode = PCI_PROBE_NORMAL; | 532 | mode = PCI_PROBE_NORMAL; |
514 | if (ppc_md.pci_probe_mode) | 533 | if (ppc_md.pci_probe_mode) |
515 | mode = ppc_md.pci_probe_mode(bus); | 534 | mode = ppc_md.pci_probe_mode(bus); |
535 | DBG(" probe mode: %d\n", mode); | ||
536 | |||
516 | if (mode == PCI_PROBE_DEVTREE) | 537 | if (mode == PCI_PROBE_DEVTREE) |
517 | of_scan_bus(node, bus); | 538 | of_scan_bus(node, bus); |
518 | else if (mode == PCI_PROBE_NORMAL) | 539 | else if (mode == PCI_PROBE_NORMAL) |
@@ -528,6 +549,8 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
528 | int i, mode; | 549 | int i, mode; |
529 | struct resource *res; | 550 | struct resource *res; |
530 | 551 | ||
552 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); | ||
553 | |||
531 | bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); | 554 | bus = pci_create_bus(NULL, hose->first_busno, hose->ops, node); |
532 | if (bus == NULL) { | 555 | if (bus == NULL) { |
533 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", | 556 | printk(KERN_ERR "Failed to create bus for PCI domain %04x\n", |
@@ -552,8 +575,9 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
552 | 575 | ||
553 | mode = PCI_PROBE_NORMAL; | 576 | mode = PCI_PROBE_NORMAL; |
554 | #ifdef CONFIG_PPC_MULTIPLATFORM | 577 | #ifdef CONFIG_PPC_MULTIPLATFORM |
555 | if (ppc_md.pci_probe_mode) | 578 | if (node && ppc_md.pci_probe_mode) |
556 | mode = ppc_md.pci_probe_mode(bus); | 579 | mode = ppc_md.pci_probe_mode(bus); |
580 | DBG(" probe mode: %d\n", mode); | ||
557 | if (mode == PCI_PROBE_DEVTREE) { | 581 | if (mode == PCI_PROBE_DEVTREE) { |
558 | bus->subordinate = hose->last_busno; | 582 | bus->subordinate = hose->last_busno; |
559 | of_scan_bus(node, bus); | 583 | of_scan_bus(node, bus); |
@@ -842,8 +866,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file, | |||
842 | * Returns a negative error code on failure, zero on success. | 866 | * Returns a negative error code on failure, zero on success. |
843 | */ | 867 | */ |
844 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | 868 | int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, |
845 | enum pci_mmap_state mmap_state, | 869 | enum pci_mmap_state mmap_state, int write_combine) |
846 | int write_combine) | ||
847 | { | 870 | { |
848 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 871 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; |
849 | struct resource *rp; | 872 | struct resource *rp; |
@@ -896,6 +919,25 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, | |||
896 | unsigned long phb_io_base_phys, | 919 | unsigned long phb_io_base_phys, |
897 | void __iomem * phb_io_base_virt) | 920 | void __iomem * phb_io_base_virt) |
898 | { | 921 | { |
922 | /* Remove these asap */ | ||
923 | |||
924 | struct pci_address { | ||
925 | u32 a_hi; | ||
926 | u32 a_mid; | ||
927 | u32 a_lo; | ||
928 | }; | ||
929 | |||
930 | struct isa_address { | ||
931 | u32 a_hi; | ||
932 | u32 a_lo; | ||
933 | }; | ||
934 | |||
935 | struct isa_range { | ||
936 | struct isa_address isa_addr; | ||
937 | struct pci_address pci_addr; | ||
938 | unsigned int size; | ||
939 | }; | ||
940 | |||
899 | struct isa_range *range; | 941 | struct isa_range *range; |
900 | unsigned long pci_addr; | 942 | unsigned long pci_addr; |
901 | unsigned int isa_addr; | 943 | unsigned int isa_addr; |
@@ -1223,6 +1265,7 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, | |||
1223 | } | 1265 | } |
1224 | EXPORT_SYMBOL(pcibios_fixup_device_resources); | 1266 | EXPORT_SYMBOL(pcibios_fixup_device_resources); |
1225 | 1267 | ||
1268 | |||
1226 | static void __devinit do_bus_setup(struct pci_bus *bus) | 1269 | static void __devinit do_bus_setup(struct pci_bus *bus) |
1227 | { | 1270 | { |
1228 | struct pci_dev *dev; | 1271 | struct pci_dev *dev; |
@@ -1306,8 +1349,38 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, | |||
1306 | *end = rsrc->end + offset; | 1349 | *end = rsrc->end + offset; |
1307 | } | 1350 | } |
1308 | 1351 | ||
1352 | struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | ||
1353 | { | ||
1354 | if (!have_of) | ||
1355 | return NULL; | ||
1356 | while(node) { | ||
1357 | struct pci_controller *hose, *tmp; | ||
1358 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) | ||
1359 | if (hose->arch_data == node) | ||
1360 | return hose; | ||
1361 | node = node->parent; | ||
1362 | } | ||
1363 | return NULL; | ||
1364 | } | ||
1365 | |||
1309 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 1366 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
1310 | 1367 | ||
1368 | unsigned long pci_address_to_pio(phys_addr_t address) | ||
1369 | { | ||
1370 | struct pci_controller *hose, *tmp; | ||
1371 | |||
1372 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
1373 | if (address >= hose->io_base_phys && | ||
1374 | address < (hose->io_base_phys + hose->pci_io_size)) { | ||
1375 | unsigned long base = | ||
1376 | (unsigned long)hose->io_base_virt - pci_io_base; | ||
1377 | return base + (address - hose->io_base_phys); | ||
1378 | } | ||
1379 | } | ||
1380 | return (unsigned int)-1; | ||
1381 | } | ||
1382 | EXPORT_SYMBOL_GPL(pci_address_to_pio); | ||
1383 | |||
1311 | 1384 | ||
1312 | #define IOBASE_BRIDGE_NUMBER 0 | 1385 | #define IOBASE_BRIDGE_NUMBER 0 |
1313 | #define IOBASE_MEMORY 1 | 1386 | #define IOBASE_MEMORY 1 |
diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index 2d333cc84082..e6fb194fe537 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c | |||
@@ -43,8 +43,13 @@ static void dummy_perf(struct pt_regs *regs) | |||
43 | mtspr(SPRN_MMCR0, mmcr0); | 43 | mtspr(SPRN_MMCR0, mmcr0); |
44 | } | 44 | } |
45 | #else | 45 | #else |
46 | /* Ensure exceptions are disabled */ | ||
46 | static void dummy_perf(struct pt_regs *regs) | 47 | static void dummy_perf(struct pt_regs *regs) |
47 | { | 48 | { |
49 | unsigned int mmcr0 = mfspr(SPRN_MMCR0); | ||
50 | |||
51 | mmcr0 &= ~(MMCR0_PMXE); | ||
52 | mtspr(SPRN_MMCR0, mmcr0); | ||
48 | } | 53 | } |
49 | #endif | 54 | #endif |
50 | 55 | ||
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 94db25708456..b2758148a0de 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -76,11 +76,6 @@ EXPORT_SYMBOL(single_step_exception); | |||
76 | EXPORT_SYMBOL(sys_sigreturn); | 76 | EXPORT_SYMBOL(sys_sigreturn); |
77 | #endif | 77 | #endif |
78 | 78 | ||
79 | #if defined(CONFIG_PPC_PREP) | ||
80 | EXPORT_SYMBOL(_prep_type); | ||
81 | EXPORT_SYMBOL(ucSystemType); | ||
82 | #endif | ||
83 | |||
84 | EXPORT_SYMBOL(strcpy); | 79 | EXPORT_SYMBOL(strcpy); |
85 | EXPORT_SYMBOL(strncpy); | 80 | EXPORT_SYMBOL(strncpy); |
86 | EXPORT_SYMBOL(strcat); | 81 | EXPORT_SYMBOL(strcat); |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 3bf968e74095..977ee3adaf2d 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/initrd.h> | 29 | #include <linux/initrd.h> |
30 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/kexec.h> | ||
32 | 33 | ||
33 | #include <asm/prom.h> | 34 | #include <asm/prom.h> |
34 | #include <asm/rtas.h> | 35 | #include <asm/rtas.h> |
@@ -37,6 +38,7 @@ | |||
37 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
39 | #include <asm/io.h> | 40 | #include <asm/io.h> |
41 | #include <asm/kdump.h> | ||
40 | #include <asm/smp.h> | 42 | #include <asm/smp.h> |
41 | #include <asm/system.h> | 43 | #include <asm/system.h> |
42 | #include <asm/mmu.h> | 44 | #include <asm/mmu.h> |
@@ -55,21 +57,6 @@ | |||
55 | #define DBG(fmt...) | 57 | #define DBG(fmt...) |
56 | #endif | 58 | #endif |
57 | 59 | ||
58 | struct pci_reg_property { | ||
59 | struct pci_address addr; | ||
60 | u32 size_hi; | ||
61 | u32 size_lo; | ||
62 | }; | ||
63 | |||
64 | struct isa_reg_property { | ||
65 | u32 space; | ||
66 | u32 address; | ||
67 | u32 size; | ||
68 | }; | ||
69 | |||
70 | |||
71 | typedef int interpret_func(struct device_node *, unsigned long *, | ||
72 | int, int, int); | ||
73 | 60 | ||
74 | static int __initdata dt_root_addr_cells; | 61 | static int __initdata dt_root_addr_cells; |
75 | static int __initdata dt_root_size_cells; | 62 | static int __initdata dt_root_size_cells; |
@@ -311,6 +298,16 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
311 | int i, j, n, sense; | 298 | int i, j, n, sense; |
312 | unsigned int *irq, virq; | 299 | unsigned int *irq, virq; |
313 | struct device_node *ic; | 300 | struct device_node *ic; |
301 | int trace = 0; | ||
302 | |||
303 | //#define TRACE(fmt...) do { if (trace) { printk(fmt); mdelay(1000); } } while(0) | ||
304 | #define TRACE(fmt...) | ||
305 | |||
306 | if (!strcmp(np->name, "smu-doorbell")) | ||
307 | trace = 1; | ||
308 | |||
309 | TRACE("Finishing SMU doorbell ! num_interrupt_controllers = %d\n", | ||
310 | num_interrupt_controllers); | ||
314 | 311 | ||
315 | if (num_interrupt_controllers == 0) { | 312 | if (num_interrupt_controllers == 0) { |
316 | /* | 313 | /* |
@@ -345,11 +342,12 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
345 | } | 342 | } |
346 | 343 | ||
347 | ints = (unsigned int *) get_property(np, "interrupts", &intlen); | 344 | ints = (unsigned int *) get_property(np, "interrupts", &intlen); |
345 | TRACE("ints=%p, intlen=%d\n", ints, intlen); | ||
348 | if (ints == NULL) | 346 | if (ints == NULL) |
349 | return 0; | 347 | return 0; |
350 | intrcells = prom_n_intr_cells(np); | 348 | intrcells = prom_n_intr_cells(np); |
351 | intlen /= intrcells * sizeof(unsigned int); | 349 | intlen /= intrcells * sizeof(unsigned int); |
352 | 350 | TRACE("intrcells=%d, new intlen=%d\n", intrcells, intlen); | |
353 | np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); | 351 | np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start); |
354 | if (!np->intrs) | 352 | if (!np->intrs) |
355 | return -ENOMEM; | 353 | return -ENOMEM; |
@@ -360,6 +358,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
360 | intrcount = 0; | 358 | intrcount = 0; |
361 | for (i = 0; i < intlen; ++i, ints += intrcells) { | 359 | for (i = 0; i < intlen; ++i, ints += intrcells) { |
362 | n = map_interrupt(&irq, &ic, np, ints, intrcells); | 360 | n = map_interrupt(&irq, &ic, np, ints, intrcells); |
361 | TRACE("map, irq=%d, ic=%p, n=%d\n", irq, ic, n); | ||
363 | if (n <= 0) | 362 | if (n <= 0) |
364 | continue; | 363 | continue; |
365 | 364 | ||
@@ -370,6 +369,7 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
370 | np->intrs[intrcount].sense = map_isa_senses[sense]; | 369 | np->intrs[intrcount].sense = map_isa_senses[sense]; |
371 | } else { | 370 | } else { |
372 | virq = virt_irq_create_mapping(irq[0]); | 371 | virq = virt_irq_create_mapping(irq[0]); |
372 | TRACE("virq=%d\n", virq); | ||
373 | #ifdef CONFIG_PPC64 | 373 | #ifdef CONFIG_PPC64 |
374 | if (virq == NO_IRQ) { | 374 | if (virq == NO_IRQ) { |
375 | printk(KERN_CRIT "Could not allocate interrupt" | 375 | printk(KERN_CRIT "Could not allocate interrupt" |
@@ -379,6 +379,12 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
379 | #endif | 379 | #endif |
380 | np->intrs[intrcount].line = irq_offset_up(virq); | 380 | np->intrs[intrcount].line = irq_offset_up(virq); |
381 | sense = (n > 1)? (irq[1] & 3): 1; | 381 | sense = (n > 1)? (irq[1] & 3): 1; |
382 | |||
383 | /* Apple uses bits in there in a different way, let's | ||
384 | * only keep the real sense bit on macs | ||
385 | */ | ||
386 | if (_machine == PLATFORM_POWERMAC) | ||
387 | sense &= 0x1; | ||
382 | np->intrs[intrcount].sense = map_mpic_senses[sense]; | 388 | np->intrs[intrcount].sense = map_mpic_senses[sense]; |
383 | } | 389 | } |
384 | 390 | ||
@@ -388,12 +394,13 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
388 | char *name = get_property(ic->parent, "name", NULL); | 394 | char *name = get_property(ic->parent, "name", NULL); |
389 | if (name && !strcmp(name, "u3")) | 395 | if (name && !strcmp(name, "u3")) |
390 | np->intrs[intrcount].line += 128; | 396 | np->intrs[intrcount].line += 128; |
391 | else if (!(name && !strcmp(name, "mac-io"))) | 397 | else if (!(name && (!strcmp(name, "mac-io") || |
398 | !strcmp(name, "u4")))) | ||
392 | /* ignore other cascaded controllers, such as | 399 | /* ignore other cascaded controllers, such as |
393 | the k2-sata-root */ | 400 | the k2-sata-root */ |
394 | break; | 401 | break; |
395 | } | 402 | } |
396 | #endif | 403 | #endif /* CONFIG_PPC64 */ |
397 | if (n > 2) { | 404 | if (n > 2) { |
398 | printk("hmmm, got %d intr cells for %s:", n, | 405 | printk("hmmm, got %d intr cells for %s:", n, |
399 | np->full_name); | 406 | np->full_name); |
@@ -408,234 +415,19 @@ static int __devinit finish_node_interrupts(struct device_node *np, | |||
408 | return 0; | 415 | return 0; |
409 | } | 416 | } |
410 | 417 | ||
411 | static int __devinit interpret_pci_props(struct device_node *np, | ||
412 | unsigned long *mem_start, | ||
413 | int naddrc, int nsizec, | ||
414 | int measure_only) | ||
415 | { | ||
416 | struct address_range *adr; | ||
417 | struct pci_reg_property *pci_addrs; | ||
418 | int i, l, n_addrs; | ||
419 | |||
420 | pci_addrs = (struct pci_reg_property *) | ||
421 | get_property(np, "assigned-addresses", &l); | ||
422 | if (!pci_addrs) | ||
423 | return 0; | ||
424 | |||
425 | n_addrs = l / sizeof(*pci_addrs); | ||
426 | |||
427 | adr = prom_alloc(n_addrs * sizeof(*adr), mem_start); | ||
428 | if (!adr) | ||
429 | return -ENOMEM; | ||
430 | |||
431 | if (measure_only) | ||
432 | return 0; | ||
433 | |||
434 | np->addrs = adr; | ||
435 | np->n_addrs = n_addrs; | ||
436 | |||
437 | for (i = 0; i < n_addrs; i++) { | ||
438 | adr[i].space = pci_addrs[i].addr.a_hi; | ||
439 | adr[i].address = pci_addrs[i].addr.a_lo | | ||
440 | ((u64)pci_addrs[i].addr.a_mid << 32); | ||
441 | adr[i].size = pci_addrs[i].size_lo; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int __init interpret_dbdma_props(struct device_node *np, | ||
448 | unsigned long *mem_start, | ||
449 | int naddrc, int nsizec, | ||
450 | int measure_only) | ||
451 | { | ||
452 | struct reg_property32 *rp; | ||
453 | struct address_range *adr; | ||
454 | unsigned long base_address; | ||
455 | int i, l; | ||
456 | struct device_node *db; | ||
457 | |||
458 | base_address = 0; | ||
459 | if (!measure_only) { | ||
460 | for (db = np->parent; db != NULL; db = db->parent) { | ||
461 | if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) { | ||
462 | base_address = db->addrs[0].address; | ||
463 | break; | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | |||
468 | rp = (struct reg_property32 *) get_property(np, "reg", &l); | ||
469 | if (rp != 0 && l >= sizeof(struct reg_property32)) { | ||
470 | i = 0; | ||
471 | adr = (struct address_range *) (*mem_start); | ||
472 | while ((l -= sizeof(struct reg_property32)) >= 0) { | ||
473 | if (!measure_only) { | ||
474 | adr[i].space = 2; | ||
475 | adr[i].address = rp[i].address + base_address; | ||
476 | adr[i].size = rp[i].size; | ||
477 | } | ||
478 | ++i; | ||
479 | } | ||
480 | np->addrs = adr; | ||
481 | np->n_addrs = i; | ||
482 | (*mem_start) += i * sizeof(struct address_range); | ||
483 | } | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int __init interpret_macio_props(struct device_node *np, | ||
489 | unsigned long *mem_start, | ||
490 | int naddrc, int nsizec, | ||
491 | int measure_only) | ||
492 | { | ||
493 | struct reg_property32 *rp; | ||
494 | struct address_range *adr; | ||
495 | unsigned long base_address; | ||
496 | int i, l; | ||
497 | struct device_node *db; | ||
498 | |||
499 | base_address = 0; | ||
500 | if (!measure_only) { | ||
501 | for (db = np->parent; db != NULL; db = db->parent) { | ||
502 | if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { | ||
503 | base_address = db->addrs[0].address; | ||
504 | break; | ||
505 | } | ||
506 | } | ||
507 | } | ||
508 | |||
509 | rp = (struct reg_property32 *) get_property(np, "reg", &l); | ||
510 | if (rp != 0 && l >= sizeof(struct reg_property32)) { | ||
511 | i = 0; | ||
512 | adr = (struct address_range *) (*mem_start); | ||
513 | while ((l -= sizeof(struct reg_property32)) >= 0) { | ||
514 | if (!measure_only) { | ||
515 | adr[i].space = 2; | ||
516 | adr[i].address = rp[i].address + base_address; | ||
517 | adr[i].size = rp[i].size; | ||
518 | } | ||
519 | ++i; | ||
520 | } | ||
521 | np->addrs = adr; | ||
522 | np->n_addrs = i; | ||
523 | (*mem_start) += i * sizeof(struct address_range); | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static int __init interpret_isa_props(struct device_node *np, | ||
530 | unsigned long *mem_start, | ||
531 | int naddrc, int nsizec, | ||
532 | int measure_only) | ||
533 | { | ||
534 | struct isa_reg_property *rp; | ||
535 | struct address_range *adr; | ||
536 | int i, l; | ||
537 | |||
538 | rp = (struct isa_reg_property *) get_property(np, "reg", &l); | ||
539 | if (rp != 0 && l >= sizeof(struct isa_reg_property)) { | ||
540 | i = 0; | ||
541 | adr = (struct address_range *) (*mem_start); | ||
542 | while ((l -= sizeof(struct isa_reg_property)) >= 0) { | ||
543 | if (!measure_only) { | ||
544 | adr[i].space = rp[i].space; | ||
545 | adr[i].address = rp[i].address; | ||
546 | adr[i].size = rp[i].size; | ||
547 | } | ||
548 | ++i; | ||
549 | } | ||
550 | np->addrs = adr; | ||
551 | np->n_addrs = i; | ||
552 | (*mem_start) += i * sizeof(struct address_range); | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int __init interpret_root_props(struct device_node *np, | ||
559 | unsigned long *mem_start, | ||
560 | int naddrc, int nsizec, | ||
561 | int measure_only) | ||
562 | { | ||
563 | struct address_range *adr; | ||
564 | int i, l; | ||
565 | unsigned int *rp; | ||
566 | int rpsize = (naddrc + nsizec) * sizeof(unsigned int); | ||
567 | |||
568 | rp = (unsigned int *) get_property(np, "reg", &l); | ||
569 | if (rp != 0 && l >= rpsize) { | ||
570 | i = 0; | ||
571 | adr = (struct address_range *) (*mem_start); | ||
572 | while ((l -= rpsize) >= 0) { | ||
573 | if (!measure_only) { | ||
574 | adr[i].space = 0; | ||
575 | adr[i].address = rp[naddrc - 1]; | ||
576 | adr[i].size = rp[naddrc + nsizec - 1]; | ||
577 | } | ||
578 | ++i; | ||
579 | rp += naddrc + nsizec; | ||
580 | } | ||
581 | np->addrs = adr; | ||
582 | np->n_addrs = i; | ||
583 | (*mem_start) += i * sizeof(struct address_range); | ||
584 | } | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int __devinit finish_node(struct device_node *np, | 418 | static int __devinit finish_node(struct device_node *np, |
590 | unsigned long *mem_start, | 419 | unsigned long *mem_start, |
591 | interpret_func *ifunc, | ||
592 | int naddrc, int nsizec, | ||
593 | int measure_only) | 420 | int measure_only) |
594 | { | 421 | { |
595 | struct device_node *child; | 422 | struct device_node *child; |
596 | int *ip, rc = 0; | 423 | int rc = 0; |
597 | |||
598 | /* get the device addresses and interrupts */ | ||
599 | if (ifunc != NULL) | ||
600 | rc = ifunc(np, mem_start, naddrc, nsizec, measure_only); | ||
601 | if (rc) | ||
602 | goto out; | ||
603 | 424 | ||
604 | rc = finish_node_interrupts(np, mem_start, measure_only); | 425 | rc = finish_node_interrupts(np, mem_start, measure_only); |
605 | if (rc) | 426 | if (rc) |
606 | goto out; | 427 | goto out; |
607 | 428 | ||
608 | /* Look for #address-cells and #size-cells properties. */ | ||
609 | ip = (int *) get_property(np, "#address-cells", NULL); | ||
610 | if (ip != NULL) | ||
611 | naddrc = *ip; | ||
612 | ip = (int *) get_property(np, "#size-cells", NULL); | ||
613 | if (ip != NULL) | ||
614 | nsizec = *ip; | ||
615 | |||
616 | if (!strcmp(np->name, "device-tree") || np->parent == NULL) | ||
617 | ifunc = interpret_root_props; | ||
618 | else if (np->type == 0) | ||
619 | ifunc = NULL; | ||
620 | else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) | ||
621 | ifunc = interpret_pci_props; | ||
622 | else if (!strcmp(np->type, "dbdma")) | ||
623 | ifunc = interpret_dbdma_props; | ||
624 | else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) | ||
625 | ifunc = interpret_macio_props; | ||
626 | else if (!strcmp(np->type, "isa")) | ||
627 | ifunc = interpret_isa_props; | ||
628 | else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) | ||
629 | ifunc = interpret_root_props; | ||
630 | else if (!((ifunc == interpret_dbdma_props | ||
631 | || ifunc == interpret_macio_props) | ||
632 | && (!strcmp(np->type, "escc") | ||
633 | || !strcmp(np->type, "media-bay")))) | ||
634 | ifunc = NULL; | ||
635 | |||
636 | for (child = np->child; child != NULL; child = child->sibling) { | 429 | for (child = np->child; child != NULL; child = child->sibling) { |
637 | rc = finish_node(child, mem_start, ifunc, | 430 | rc = finish_node(child, mem_start, measure_only); |
638 | naddrc, nsizec, measure_only); | ||
639 | if (rc) | 431 | if (rc) |
640 | goto out; | 432 | goto out; |
641 | } | 433 | } |
@@ -697,10 +489,10 @@ void __init finish_device_tree(void) | |||
697 | * reason and then remove those additional 16 bytes | 489 | * reason and then remove those additional 16 bytes |
698 | */ | 490 | */ |
699 | size = 16; | 491 | size = 16; |
700 | finish_node(allnodes, &size, NULL, 0, 0, 1); | 492 | finish_node(allnodes, &size, 1); |
701 | size -= 16; | 493 | size -= 16; |
702 | end = start = (unsigned long) __va(lmb_alloc(size, 128)); | 494 | end = start = (unsigned long) __va(lmb_alloc(size, 128)); |
703 | finish_node(allnodes, &end, NULL, 0, 0, 0); | 495 | finish_node(allnodes, &end, 0); |
704 | BUG_ON(end != start + size); | 496 | BUG_ON(end != start + size); |
705 | 497 | ||
706 | DBG(" <- finish_device_tree\n"); | 498 | DBG(" <- finish_device_tree\n"); |
@@ -1197,6 +989,16 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1197 | } | 989 | } |
1198 | #endif /* CONFIG_PPC_RTAS */ | 990 | #endif /* CONFIG_PPC_RTAS */ |
1199 | 991 | ||
992 | #ifdef CONFIG_KEXEC | ||
993 | lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-base", NULL); | ||
994 | if (lprop) | ||
995 | crashk_res.start = *lprop; | ||
996 | |||
997 | lprop = (u64*)of_get_flat_dt_prop(node, "linux,crashkernel-size", NULL); | ||
998 | if (lprop) | ||
999 | crashk_res.end = crashk_res.start + *lprop - 1; | ||
1000 | #endif | ||
1001 | |||
1200 | /* break now */ | 1002 | /* break now */ |
1201 | return 1; | 1003 | return 1; |
1202 | } | 1004 | } |
@@ -1263,7 +1065,9 @@ static int __init early_init_dt_scan_memory(unsigned long node, | |||
1263 | } else if (strcmp(type, "memory") != 0) | 1065 | } else if (strcmp(type, "memory") != 0) |
1264 | return 0; | 1066 | return 0; |
1265 | 1067 | ||
1266 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); | 1068 | reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); |
1069 | if (reg == NULL) | ||
1070 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); | ||
1267 | if (reg == NULL) | 1071 | if (reg == NULL) |
1268 | return 0; | 1072 | return 0; |
1269 | 1073 | ||
@@ -1335,11 +1139,14 @@ void __init early_init_devtree(void *params) | |||
1335 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | 1139 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); |
1336 | lmb_enforce_memory_limit(memory_limit); | 1140 | lmb_enforce_memory_limit(memory_limit); |
1337 | lmb_analyze(); | 1141 | lmb_analyze(); |
1338 | lmb_reserve(0, __pa(klimit)); | ||
1339 | 1142 | ||
1340 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | 1143 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); |
1341 | 1144 | ||
1342 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ | 1145 | /* Reserve LMB regions used by kernel, initrd, dt, etc... */ |
1146 | lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); | ||
1147 | #ifdef CONFIG_CRASH_DUMP | ||
1148 | lmb_reserve(0, KDUMP_RESERVE_LIMIT); | ||
1149 | #endif | ||
1343 | early_reserve_mem(); | 1150 | early_reserve_mem(); |
1344 | 1151 | ||
1345 | DBG("Scanning CPUs ...\n"); | 1152 | DBG("Scanning CPUs ...\n"); |
@@ -1802,7 +1609,6 @@ static void of_node_release(struct kref *kref) | |||
1802 | prop = next; | 1609 | prop = next; |
1803 | } | 1610 | } |
1804 | kfree(node->intrs); | 1611 | kfree(node->intrs); |
1805 | kfree(node->addrs); | ||
1806 | kfree(node->full_name); | 1612 | kfree(node->full_name); |
1807 | kfree(node->data); | 1613 | kfree(node->data); |
1808 | kfree(node); | 1614 | kfree(node); |
@@ -1884,9 +1690,7 @@ void of_detach_node(const struct device_node *np) | |||
1884 | * This should probably be split up into smaller chunks. | 1690 | * This should probably be split up into smaller chunks. |
1885 | */ | 1691 | */ |
1886 | 1692 | ||
1887 | static int of_finish_dynamic_node(struct device_node *node, | 1693 | static int of_finish_dynamic_node(struct device_node *node) |
1888 | unsigned long *unused1, int unused2, | ||
1889 | int unused3, int unused4) | ||
1890 | { | 1694 | { |
1891 | struct device_node *parent = of_get_parent(node); | 1695 | struct device_node *parent = of_get_parent(node); |
1892 | int err = 0; | 1696 | int err = 0; |
@@ -1907,7 +1711,8 @@ static int of_finish_dynamic_node(struct device_node *node, | |||
1907 | return -ENODEV; | 1711 | return -ENODEV; |
1908 | 1712 | ||
1909 | /* fix up new node's linux_phandle field */ | 1713 | /* fix up new node's linux_phandle field */ |
1910 | if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) | 1714 | if ((ibm_phandle = (unsigned int *)get_property(node, |
1715 | "ibm,phandle", NULL))) | ||
1911 | node->linux_phandle = *ibm_phandle; | 1716 | node->linux_phandle = *ibm_phandle; |
1912 | 1717 | ||
1913 | out: | 1718 | out: |
@@ -1922,7 +1727,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb, | |||
1922 | 1727 | ||
1923 | switch (action) { | 1728 | switch (action) { |
1924 | case PSERIES_RECONFIG_ADD: | 1729 | case PSERIES_RECONFIG_ADD: |
1925 | err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0); | 1730 | err = of_finish_dynamic_node(node); |
1731 | if (!err) | ||
1732 | finish_node(node, NULL, 0); | ||
1926 | if (err < 0) { | 1733 | if (err < 0) { |
1927 | printk(KERN_ERR "finish_node returned %d\n", err); | 1734 | printk(KERN_ERR "finish_node returned %d\n", err); |
1928 | err = NOTIFY_BAD; | 1735 | err = NOTIFY_BAD; |
@@ -1996,175 +1803,4 @@ int prom_add_property(struct device_node* np, struct property* prop) | |||
1996 | return 0; | 1803 | return 0; |
1997 | } | 1804 | } |
1998 | 1805 | ||
1999 | /* I quickly hacked that one, check against spec ! */ | ||
2000 | static inline unsigned long | ||
2001 | bus_space_to_resource_flags(unsigned int bus_space) | ||
2002 | { | ||
2003 | u8 space = (bus_space >> 24) & 0xf; | ||
2004 | if (space == 0) | ||
2005 | space = 0x02; | ||
2006 | if (space == 0x02) | ||
2007 | return IORESOURCE_MEM; | ||
2008 | else if (space == 0x01) | ||
2009 | return IORESOURCE_IO; | ||
2010 | else { | ||
2011 | printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", | ||
2012 | bus_space); | ||
2013 | return 0; | ||
2014 | } | ||
2015 | } | ||
2016 | |||
2017 | #ifdef CONFIG_PCI | ||
2018 | static struct resource *find_parent_pci_resource(struct pci_dev* pdev, | ||
2019 | struct address_range *range) | ||
2020 | { | ||
2021 | unsigned long mask; | ||
2022 | int i; | ||
2023 | |||
2024 | /* Check this one */ | ||
2025 | mask = bus_space_to_resource_flags(range->space); | ||
2026 | for (i=0; i<DEVICE_COUNT_RESOURCE; i++) { | ||
2027 | if ((pdev->resource[i].flags & mask) == mask && | ||
2028 | pdev->resource[i].start <= range->address && | ||
2029 | pdev->resource[i].end > range->address) { | ||
2030 | if ((range->address + range->size - 1) > pdev->resource[i].end) { | ||
2031 | /* Add better message */ | ||
2032 | printk(KERN_WARNING "PCI/OF resource overlap !\n"); | ||
2033 | return NULL; | ||
2034 | } | ||
2035 | break; | ||
2036 | } | ||
2037 | } | ||
2038 | if (i == DEVICE_COUNT_RESOURCE) | ||
2039 | return NULL; | ||
2040 | return &pdev->resource[i]; | ||
2041 | } | ||
2042 | |||
2043 | /* | ||
2044 | * Request an OF device resource. Currently handles child of PCI devices, | ||
2045 | * or other nodes attached to the root node. Ultimately, put some | ||
2046 | * link to resources in the OF node. | ||
2047 | */ | ||
2048 | struct resource *request_OF_resource(struct device_node* node, int index, | ||
2049 | const char* name_postfix) | ||
2050 | { | ||
2051 | struct pci_dev* pcidev; | ||
2052 | u8 pci_bus, pci_devfn; | ||
2053 | unsigned long iomask; | ||
2054 | struct device_node* nd; | ||
2055 | struct resource* parent; | ||
2056 | struct resource *res = NULL; | ||
2057 | int nlen, plen; | ||
2058 | |||
2059 | if (index >= node->n_addrs) | ||
2060 | goto fail; | ||
2061 | |||
2062 | /* Sanity check on bus space */ | ||
2063 | iomask = bus_space_to_resource_flags(node->addrs[index].space); | ||
2064 | if (iomask & IORESOURCE_MEM) | ||
2065 | parent = &iomem_resource; | ||
2066 | else if (iomask & IORESOURCE_IO) | ||
2067 | parent = &ioport_resource; | ||
2068 | else | ||
2069 | goto fail; | ||
2070 | |||
2071 | /* Find a PCI parent if any */ | ||
2072 | nd = node; | ||
2073 | pcidev = NULL; | ||
2074 | while (nd) { | ||
2075 | if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) | ||
2076 | pcidev = pci_find_slot(pci_bus, pci_devfn); | ||
2077 | if (pcidev) break; | ||
2078 | nd = nd->parent; | ||
2079 | } | ||
2080 | if (pcidev) | ||
2081 | parent = find_parent_pci_resource(pcidev, &node->addrs[index]); | ||
2082 | if (!parent) { | ||
2083 | printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", | ||
2084 | node->name); | ||
2085 | goto fail; | ||
2086 | } | ||
2087 | 1806 | ||
2088 | res = __request_region(parent, node->addrs[index].address, | ||
2089 | node->addrs[index].size, NULL); | ||
2090 | if (!res) | ||
2091 | goto fail; | ||
2092 | nlen = strlen(node->name); | ||
2093 | plen = name_postfix ? strlen(name_postfix) : 0; | ||
2094 | res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); | ||
2095 | if (res->name) { | ||
2096 | strcpy((char *)res->name, node->name); | ||
2097 | if (plen) | ||
2098 | strcpy((char *)res->name+nlen, name_postfix); | ||
2099 | } | ||
2100 | return res; | ||
2101 | fail: | ||
2102 | return NULL; | ||
2103 | } | ||
2104 | EXPORT_SYMBOL(request_OF_resource); | ||
2105 | |||
2106 | int release_OF_resource(struct device_node *node, int index) | ||
2107 | { | ||
2108 | struct pci_dev* pcidev; | ||
2109 | u8 pci_bus, pci_devfn; | ||
2110 | unsigned long iomask, start, end; | ||
2111 | struct device_node* nd; | ||
2112 | struct resource* parent; | ||
2113 | struct resource *res = NULL; | ||
2114 | |||
2115 | if (index >= node->n_addrs) | ||
2116 | return -EINVAL; | ||
2117 | |||
2118 | /* Sanity check on bus space */ | ||
2119 | iomask = bus_space_to_resource_flags(node->addrs[index].space); | ||
2120 | if (iomask & IORESOURCE_MEM) | ||
2121 | parent = &iomem_resource; | ||
2122 | else if (iomask & IORESOURCE_IO) | ||
2123 | parent = &ioport_resource; | ||
2124 | else | ||
2125 | return -EINVAL; | ||
2126 | |||
2127 | /* Find a PCI parent if any */ | ||
2128 | nd = node; | ||
2129 | pcidev = NULL; | ||
2130 | while(nd) { | ||
2131 | if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) | ||
2132 | pcidev = pci_find_slot(pci_bus, pci_devfn); | ||
2133 | if (pcidev) break; | ||
2134 | nd = nd->parent; | ||
2135 | } | ||
2136 | if (pcidev) | ||
2137 | parent = find_parent_pci_resource(pcidev, &node->addrs[index]); | ||
2138 | if (!parent) { | ||
2139 | printk(KERN_WARNING "release_OF_resource(%s), parent not found\n", | ||
2140 | node->name); | ||
2141 | return -ENODEV; | ||
2142 | } | ||
2143 | |||
2144 | /* Find us in the parent and its childs */ | ||
2145 | res = parent->child; | ||
2146 | start = node->addrs[index].address; | ||
2147 | end = start + node->addrs[index].size - 1; | ||
2148 | while (res) { | ||
2149 | if (res->start == start && res->end == end && | ||
2150 | (res->flags & IORESOURCE_BUSY)) | ||
2151 | break; | ||
2152 | if (res->start <= start && res->end >= end) | ||
2153 | res = res->child; | ||
2154 | else | ||
2155 | res = res->sibling; | ||
2156 | } | ||
2157 | if (!res) | ||
2158 | return -ENODEV; | ||
2159 | |||
2160 | if (res->name) { | ||
2161 | kfree(res->name); | ||
2162 | res->name = NULL; | ||
2163 | } | ||
2164 | release_resource(res); | ||
2165 | kfree(res); | ||
2166 | |||
2167 | return 0; | ||
2168 | } | ||
2169 | EXPORT_SYMBOL(release_OF_resource); | ||
2170 | #endif /* CONFIG_PCI */ | ||
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index bcdc209dca85..e381f2fc121c 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -192,6 +192,11 @@ static unsigned long __initdata alloc_bottom; | |||
192 | static unsigned long __initdata rmo_top; | 192 | static unsigned long __initdata rmo_top; |
193 | static unsigned long __initdata ram_top; | 193 | static unsigned long __initdata ram_top; |
194 | 194 | ||
195 | #ifdef CONFIG_KEXEC | ||
196 | static unsigned long __initdata prom_crashk_base; | ||
197 | static unsigned long __initdata prom_crashk_size; | ||
198 | #endif | ||
199 | |||
195 | static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; | 200 | static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; |
196 | static int __initdata mem_reserve_cnt; | 201 | static int __initdata mem_reserve_cnt; |
197 | 202 | ||
@@ -553,7 +558,8 @@ unsigned long prom_memparse(const char *ptr, const char **retptr) | |||
553 | static void __init early_cmdline_parse(void) | 558 | static void __init early_cmdline_parse(void) |
554 | { | 559 | { |
555 | struct prom_t *_prom = &RELOC(prom); | 560 | struct prom_t *_prom = &RELOC(prom); |
556 | char *opt, *p; | 561 | const char *opt; |
562 | char *p; | ||
557 | int l = 0; | 563 | int l = 0; |
558 | 564 | ||
559 | RELOC(prom_cmd_line[0]) = 0; | 565 | RELOC(prom_cmd_line[0]) = 0; |
@@ -590,6 +596,34 @@ static void __init early_cmdline_parse(void) | |||
590 | RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000); | 596 | RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000); |
591 | #endif | 597 | #endif |
592 | } | 598 | } |
599 | |||
600 | #ifdef CONFIG_KEXEC | ||
601 | /* | ||
602 | * crashkernel=size@addr specifies the location to reserve for | ||
603 | * crash kernel. | ||
604 | */ | ||
605 | opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel=")); | ||
606 | if (opt) { | ||
607 | opt += 12; | ||
608 | RELOC(prom_crashk_size) = prom_memparse(opt, &opt); | ||
609 | |||
610 | if (ALIGN(RELOC(prom_crashk_size), 0x1000000) != | ||
611 | RELOC(prom_crashk_size)) { | ||
612 | prom_printf("Warning: crashkernel size is not " | ||
613 | "aligned to 16MB\n"); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * At present, the crash kernel always run at 32MB. | ||
618 | * Just ignore whatever user passed. | ||
619 | */ | ||
620 | RELOC(prom_crashk_base) = 0x2000000; | ||
621 | if (*opt == '@') { | ||
622 | prom_printf("Warning: PPC64 kdump kernel always runs " | ||
623 | "at 32 MB\n"); | ||
624 | } | ||
625 | } | ||
626 | #endif | ||
593 | } | 627 | } |
594 | 628 | ||
595 | #ifdef CONFIG_PPC_PSERIES | 629 | #ifdef CONFIG_PPC_PSERIES |
@@ -1011,6 +1045,12 @@ static void __init prom_init_mem(void) | |||
1011 | prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); | 1045 | prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); |
1012 | prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); | 1046 | prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); |
1013 | prom_printf(" ram_top : %x\n", RELOC(ram_top)); | 1047 | prom_printf(" ram_top : %x\n", RELOC(ram_top)); |
1048 | #ifdef CONFIG_KEXEC | ||
1049 | if (RELOC(prom_crashk_base)) { | ||
1050 | prom_printf(" crashk_base : %x\n", RELOC(prom_crashk_base)); | ||
1051 | prom_printf(" crashk_size : %x\n", RELOC(prom_crashk_size)); | ||
1052 | } | ||
1053 | #endif | ||
1014 | } | 1054 | } |
1015 | 1055 | ||
1016 | 1056 | ||
@@ -1500,6 +1540,8 @@ static int __init prom_find_machine_type(void) | |||
1500 | #ifdef CONFIG_PPC64 | 1540 | #ifdef CONFIG_PPC64 |
1501 | if (strstr(p, RELOC("Momentum,Maple"))) | 1541 | if (strstr(p, RELOC("Momentum,Maple"))) |
1502 | return PLATFORM_MAPLE; | 1542 | return PLATFORM_MAPLE; |
1543 | if (strstr(p, RELOC("IBM,CPB"))) | ||
1544 | return PLATFORM_CELL; | ||
1503 | #endif | 1545 | #endif |
1504 | i += sl + 1; | 1546 | i += sl + 1; |
1505 | } | 1547 | } |
@@ -1994,7 +2036,7 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4) | |||
1994 | if (r3 && r4 && r4 != 0xdeadbeef) { | 2036 | if (r3 && r4 && r4 != 0xdeadbeef) { |
1995 | unsigned long val; | 2037 | unsigned long val; |
1996 | 2038 | ||
1997 | RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; | 2039 | RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3; |
1998 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; | 2040 | RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; |
1999 | 2041 | ||
2000 | val = RELOC(prom_initrd_start); | 2042 | val = RELOC(prom_initrd_start); |
@@ -2094,6 +2136,10 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2094 | */ | 2136 | */ |
2095 | prom_init_mem(); | 2137 | prom_init_mem(); |
2096 | 2138 | ||
2139 | #ifdef CONFIG_KEXEC | ||
2140 | if (RELOC(prom_crashk_base)) | ||
2141 | reserve_mem(RELOC(prom_crashk_base), RELOC(prom_crashk_size)); | ||
2142 | #endif | ||
2097 | /* | 2143 | /* |
2098 | * Determine which cpu is actually running right _now_ | 2144 | * Determine which cpu is actually running right _now_ |
2099 | */ | 2145 | */ |
@@ -2150,6 +2196,16 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
2150 | } | 2196 | } |
2151 | #endif | 2197 | #endif |
2152 | 2198 | ||
2199 | #ifdef CONFIG_KEXEC | ||
2200 | if (RELOC(prom_crashk_base)) { | ||
2201 | prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-base", | ||
2202 | PTRRELOC(&prom_crashk_base), | ||
2203 | sizeof(RELOC(prom_crashk_base))); | ||
2204 | prom_setprop(_prom->chosen, "/chosen", "linux,crashkernel-size", | ||
2205 | PTRRELOC(&prom_crashk_size), | ||
2206 | sizeof(RELOC(prom_crashk_size))); | ||
2207 | } | ||
2208 | #endif | ||
2153 | /* | 2209 | /* |
2154 | * Fixup any known bugs in the device-tree | 2210 | * Fixup any known bugs in the device-tree |
2155 | */ | 2211 | */ |
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c new file mode 100644 index 000000000000..309ae1d5fa77 --- /dev/null +++ b/arch/powerpc/kernel/prom_parse.c | |||
@@ -0,0 +1,547 @@ | |||
1 | #undef DEBUG | ||
2 | |||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/string.h> | ||
5 | #include <linux/pci_regs.h> | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/ioport.h> | ||
8 | #include <asm/prom.h> | ||
9 | #include <asm/pci-bridge.h> | ||
10 | |||
11 | #ifdef DEBUG | ||
12 | #define DBG(fmt...) do { printk(fmt); } while(0) | ||
13 | #else | ||
14 | #define DBG(fmt...) do { } while(0) | ||
15 | #endif | ||
16 | |||
17 | #ifdef CONFIG_PPC64 | ||
18 | #define PRu64 "%lx" | ||
19 | #else | ||
20 | #define PRu64 "%llx" | ||
21 | #endif | ||
22 | |||
23 | /* Max address size we deal with */ | ||
24 | #define OF_MAX_ADDR_CELLS 4 | ||
25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ | ||
26 | (ns) > 0) | ||
27 | |||
28 | /* Debug utility */ | ||
29 | #ifdef DEBUG | ||
30 | static void of_dump_addr(const char *s, u32 *addr, int na) | ||
31 | { | ||
32 | printk("%s", s); | ||
33 | while(na--) | ||
34 | printk(" %08x", *(addr++)); | ||
35 | printk("\n"); | ||
36 | } | ||
37 | #else | ||
38 | static void of_dump_addr(const char *s, u32 *addr, int na) { } | ||
39 | #endif | ||
40 | |||
41 | /* Read a big address */ | ||
42 | static inline u64 of_read_addr(u32 *cell, int size) | ||
43 | { | ||
44 | u64 r = 0; | ||
45 | while (size--) | ||
46 | r = (r << 32) | *(cell++); | ||
47 | return r; | ||
48 | } | ||
49 | |||
50 | /* Callbacks for bus specific translators */ | ||
51 | struct of_bus { | ||
52 | const char *name; | ||
53 | const char *addresses; | ||
54 | int (*match)(struct device_node *parent); | ||
55 | void (*count_cells)(struct device_node *child, | ||
56 | int *addrc, int *sizec); | ||
57 | u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); | ||
58 | int (*translate)(u32 *addr, u64 offset, int na); | ||
59 | unsigned int (*get_flags)(u32 *addr); | ||
60 | }; | ||
61 | |||
62 | |||
63 | /* | ||
64 | * Default translator (generic bus) | ||
65 | */ | ||
66 | |||
67 | static void of_bus_default_count_cells(struct device_node *dev, | ||
68 | int *addrc, int *sizec) | ||
69 | { | ||
70 | if (addrc) | ||
71 | *addrc = prom_n_addr_cells(dev); | ||
72 | if (sizec) | ||
73 | *sizec = prom_n_size_cells(dev); | ||
74 | } | ||
75 | |||
76 | static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
77 | { | ||
78 | u64 cp, s, da; | ||
79 | |||
80 | cp = of_read_addr(range, na); | ||
81 | s = of_read_addr(range + na + pna, ns); | ||
82 | da = of_read_addr(addr, na); | ||
83 | |||
84 | DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n", | ||
85 | cp, s, da); | ||
86 | |||
87 | if (da < cp || da >= (cp + s)) | ||
88 | return OF_BAD_ADDR; | ||
89 | return da - cp; | ||
90 | } | ||
91 | |||
92 | static int of_bus_default_translate(u32 *addr, u64 offset, int na) | ||
93 | { | ||
94 | u64 a = of_read_addr(addr, na); | ||
95 | memset(addr, 0, na * 4); | ||
96 | a += offset; | ||
97 | if (na > 1) | ||
98 | addr[na - 2] = a >> 32; | ||
99 | addr[na - 1] = a & 0xffffffffu; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static unsigned int of_bus_default_get_flags(u32 *addr) | ||
105 | { | ||
106 | return IORESOURCE_MEM; | ||
107 | } | ||
108 | |||
109 | |||
110 | /* | ||
111 | * PCI bus specific translator | ||
112 | */ | ||
113 | |||
114 | static int of_bus_pci_match(struct device_node *np) | ||
115 | { | ||
116 | return !strcmp(np->type, "pci"); | ||
117 | } | ||
118 | |||
119 | static void of_bus_pci_count_cells(struct device_node *np, | ||
120 | int *addrc, int *sizec) | ||
121 | { | ||
122 | if (addrc) | ||
123 | *addrc = 3; | ||
124 | if (sizec) | ||
125 | *sizec = 2; | ||
126 | } | ||
127 | |||
128 | static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
129 | { | ||
130 | u64 cp, s, da; | ||
131 | |||
132 | /* Check address type match */ | ||
133 | if ((addr[0] ^ range[0]) & 0x03000000) | ||
134 | return OF_BAD_ADDR; | ||
135 | |||
136 | /* Read address values, skipping high cell */ | ||
137 | cp = of_read_addr(range + 1, na - 1); | ||
138 | s = of_read_addr(range + na + pna, ns); | ||
139 | da = of_read_addr(addr + 1, na - 1); | ||
140 | |||
141 | DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); | ||
142 | |||
143 | if (da < cp || da >= (cp + s)) | ||
144 | return OF_BAD_ADDR; | ||
145 | return da - cp; | ||
146 | } | ||
147 | |||
148 | static int of_bus_pci_translate(u32 *addr, u64 offset, int na) | ||
149 | { | ||
150 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
151 | } | ||
152 | |||
153 | static unsigned int of_bus_pci_get_flags(u32 *addr) | ||
154 | { | ||
155 | unsigned int flags = 0; | ||
156 | u32 w = addr[0]; | ||
157 | |||
158 | switch((w >> 24) & 0x03) { | ||
159 | case 0x01: | ||
160 | flags |= IORESOURCE_IO; | ||
161 | case 0x02: /* 32 bits */ | ||
162 | case 0x03: /* 64 bits */ | ||
163 | flags |= IORESOURCE_MEM; | ||
164 | } | ||
165 | if (w & 0x40000000) | ||
166 | flags |= IORESOURCE_PREFETCH; | ||
167 | return flags; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * ISA bus specific translator | ||
172 | */ | ||
173 | |||
174 | static int of_bus_isa_match(struct device_node *np) | ||
175 | { | ||
176 | return !strcmp(np->name, "isa"); | ||
177 | } | ||
178 | |||
179 | static void of_bus_isa_count_cells(struct device_node *child, | ||
180 | int *addrc, int *sizec) | ||
181 | { | ||
182 | if (addrc) | ||
183 | *addrc = 2; | ||
184 | if (sizec) | ||
185 | *sizec = 1; | ||
186 | } | ||
187 | |||
188 | static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) | ||
189 | { | ||
190 | u64 cp, s, da; | ||
191 | |||
192 | /* Check address type match */ | ||
193 | if ((addr[0] ^ range[0]) & 0x00000001) | ||
194 | return OF_BAD_ADDR; | ||
195 | |||
196 | /* Read address values, skipping high cell */ | ||
197 | cp = of_read_addr(range + 1, na - 1); | ||
198 | s = of_read_addr(range + na + pna, ns); | ||
199 | da = of_read_addr(addr + 1, na - 1); | ||
200 | |||
201 | DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); | ||
202 | |||
203 | if (da < cp || da >= (cp + s)) | ||
204 | return OF_BAD_ADDR; | ||
205 | return da - cp; | ||
206 | } | ||
207 | |||
208 | static int of_bus_isa_translate(u32 *addr, u64 offset, int na) | ||
209 | { | ||
210 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
211 | } | ||
212 | |||
213 | static unsigned int of_bus_isa_get_flags(u32 *addr) | ||
214 | { | ||
215 | unsigned int flags = 0; | ||
216 | u32 w = addr[0]; | ||
217 | |||
218 | if (w & 1) | ||
219 | flags |= IORESOURCE_IO; | ||
220 | else | ||
221 | flags |= IORESOURCE_MEM; | ||
222 | return flags; | ||
223 | } | ||
224 | |||
225 | |||
226 | /* | ||
227 | * Array of bus specific translators | ||
228 | */ | ||
229 | |||
230 | static struct of_bus of_busses[] = { | ||
231 | /* PCI */ | ||
232 | { | ||
233 | .name = "pci", | ||
234 | .addresses = "assigned-addresses", | ||
235 | .match = of_bus_pci_match, | ||
236 | .count_cells = of_bus_pci_count_cells, | ||
237 | .map = of_bus_pci_map, | ||
238 | .translate = of_bus_pci_translate, | ||
239 | .get_flags = of_bus_pci_get_flags, | ||
240 | }, | ||
241 | /* ISA */ | ||
242 | { | ||
243 | .name = "isa", | ||
244 | .addresses = "reg", | ||
245 | .match = of_bus_isa_match, | ||
246 | .count_cells = of_bus_isa_count_cells, | ||
247 | .map = of_bus_isa_map, | ||
248 | .translate = of_bus_isa_translate, | ||
249 | .get_flags = of_bus_isa_get_flags, | ||
250 | }, | ||
251 | /* Default */ | ||
252 | { | ||
253 | .name = "default", | ||
254 | .addresses = "reg", | ||
255 | .match = NULL, | ||
256 | .count_cells = of_bus_default_count_cells, | ||
257 | .map = of_bus_default_map, | ||
258 | .translate = of_bus_default_translate, | ||
259 | .get_flags = of_bus_default_get_flags, | ||
260 | }, | ||
261 | }; | ||
262 | |||
263 | static struct of_bus *of_match_bus(struct device_node *np) | ||
264 | { | ||
265 | int i; | ||
266 | |||
267 | for (i = 0; i < ARRAY_SIZE(of_busses); i ++) | ||
268 | if (!of_busses[i].match || of_busses[i].match(np)) | ||
269 | return &of_busses[i]; | ||
270 | BUG(); | ||
271 | return NULL; | ||
272 | } | ||
273 | |||
274 | static int of_translate_one(struct device_node *parent, struct of_bus *bus, | ||
275 | struct of_bus *pbus, u32 *addr, | ||
276 | int na, int ns, int pna) | ||
277 | { | ||
278 | u32 *ranges; | ||
279 | unsigned int rlen; | ||
280 | int rone; | ||
281 | u64 offset = OF_BAD_ADDR; | ||
282 | |||
283 | /* Normally, an absence of a "ranges" property means we are | ||
284 | * crossing a non-translatable boundary, and thus the addresses | ||
285 | * below the current not cannot be converted to CPU physical ones. | ||
286 | * Unfortunately, while this is very clear in the spec, it's not | ||
287 | * what Apple understood, and they do have things like /uni-n or | ||
288 | * /ht nodes with no "ranges" property and a lot of perfectly | ||
289 | * useable mapped devices below them. Thus we treat the absence of | ||
290 | * "ranges" as equivalent to an empty "ranges" property which means | ||
291 | * a 1:1 translation at that level. It's up to the caller not to try | ||
292 | * to translate addresses that aren't supposed to be translated in | ||
293 | * the first place. --BenH. | ||
294 | */ | ||
295 | ranges = (u32 *)get_property(parent, "ranges", &rlen); | ||
296 | if (ranges == NULL || rlen == 0) { | ||
297 | offset = of_read_addr(addr, na); | ||
298 | memset(addr, 0, pna * 4); | ||
299 | DBG("OF: no ranges, 1:1 translation\n"); | ||
300 | goto finish; | ||
301 | } | ||
302 | |||
303 | DBG("OF: walking ranges...\n"); | ||
304 | |||
305 | /* Now walk through the ranges */ | ||
306 | rlen /= 4; | ||
307 | rone = na + pna + ns; | ||
308 | for (; rlen >= rone; rlen -= rone, ranges += rone) { | ||
309 | offset = bus->map(addr, ranges, na, ns, pna); | ||
310 | if (offset != OF_BAD_ADDR) | ||
311 | break; | ||
312 | } | ||
313 | if (offset == OF_BAD_ADDR) { | ||
314 | DBG("OF: not found !\n"); | ||
315 | return 1; | ||
316 | } | ||
317 | memcpy(addr, ranges + na, 4 * pna); | ||
318 | |||
319 | finish: | ||
320 | of_dump_addr("OF: parent translation for:", addr, pna); | ||
321 | DBG("OF: with offset: "PRu64"\n", offset); | ||
322 | |||
323 | /* Translate it into parent bus space */ | ||
324 | return pbus->translate(addr, offset, pna); | ||
325 | } | ||
326 | |||
327 | |||
328 | /* | ||
329 | * Translate an address from the device-tree into a CPU physical address, | ||
330 | * this walks up the tree and applies the various bus mappings on the | ||
331 | * way. | ||
332 | * | ||
333 | * Note: We consider that crossing any level with #size-cells == 0 to mean | ||
334 | * that translation is impossible (that is we are not dealing with a value | ||
335 | * that can be mapped to a cpu physical address). This is not really specified | ||
336 | * that way, but this is traditionally the way IBM at least do things | ||
337 | */ | ||
338 | u64 of_translate_address(struct device_node *dev, u32 *in_addr) | ||
339 | { | ||
340 | struct device_node *parent = NULL; | ||
341 | struct of_bus *bus, *pbus; | ||
342 | u32 addr[OF_MAX_ADDR_CELLS]; | ||
343 | int na, ns, pna, pns; | ||
344 | u64 result = OF_BAD_ADDR; | ||
345 | |||
346 | DBG("OF: ** translation for device %s **\n", dev->full_name); | ||
347 | |||
348 | /* Increase refcount at current level */ | ||
349 | of_node_get(dev); | ||
350 | |||
351 | /* Get parent & match bus type */ | ||
352 | parent = of_get_parent(dev); | ||
353 | if (parent == NULL) | ||
354 | goto bail; | ||
355 | bus = of_match_bus(parent); | ||
356 | |||
357 | /* Cound address cells & copy address locally */ | ||
358 | bus->count_cells(dev, &na, &ns); | ||
359 | if (!OF_CHECK_COUNTS(na, ns)) { | ||
360 | printk(KERN_ERR "prom_parse: Bad cell count for %s\n", | ||
361 | dev->full_name); | ||
362 | goto bail; | ||
363 | } | ||
364 | memcpy(addr, in_addr, na * 4); | ||
365 | |||
366 | DBG("OF: bus is %s (na=%d, ns=%d) on %s\n", | ||
367 | bus->name, na, ns, parent->full_name); | ||
368 | of_dump_addr("OF: translating address:", addr, na); | ||
369 | |||
370 | /* Translate */ | ||
371 | for (;;) { | ||
372 | /* Switch to parent bus */ | ||
373 | of_node_put(dev); | ||
374 | dev = parent; | ||
375 | parent = of_get_parent(dev); | ||
376 | |||
377 | /* If root, we have finished */ | ||
378 | if (parent == NULL) { | ||
379 | DBG("OF: reached root node\n"); | ||
380 | result = of_read_addr(addr, na); | ||
381 | break; | ||
382 | } | ||
383 | |||
384 | /* Get new parent bus and counts */ | ||
385 | pbus = of_match_bus(parent); | ||
386 | pbus->count_cells(dev, &pna, &pns); | ||
387 | if (!OF_CHECK_COUNTS(pna, pns)) { | ||
388 | printk(KERN_ERR "prom_parse: Bad cell count for %s\n", | ||
389 | dev->full_name); | ||
390 | break; | ||
391 | } | ||
392 | |||
393 | DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n", | ||
394 | pbus->name, pna, pns, parent->full_name); | ||
395 | |||
396 | /* Apply bus translation */ | ||
397 | if (of_translate_one(dev, bus, pbus, addr, na, ns, pna)) | ||
398 | break; | ||
399 | |||
400 | /* Complete the move up one level */ | ||
401 | na = pna; | ||
402 | ns = pns; | ||
403 | bus = pbus; | ||
404 | |||
405 | of_dump_addr("OF: one level translation:", addr, na); | ||
406 | } | ||
407 | bail: | ||
408 | of_node_put(parent); | ||
409 | of_node_put(dev); | ||
410 | |||
411 | return result; | ||
412 | } | ||
413 | EXPORT_SYMBOL(of_translate_address); | ||
414 | |||
415 | u32 *of_get_address(struct device_node *dev, int index, u64 *size, | ||
416 | unsigned int *flags) | ||
417 | { | ||
418 | u32 *prop; | ||
419 | unsigned int psize; | ||
420 | struct device_node *parent; | ||
421 | struct of_bus *bus; | ||
422 | int onesize, i, na, ns; | ||
423 | |||
424 | /* Get parent & match bus type */ | ||
425 | parent = of_get_parent(dev); | ||
426 | if (parent == NULL) | ||
427 | return NULL; | ||
428 | bus = of_match_bus(parent); | ||
429 | bus->count_cells(dev, &na, &ns); | ||
430 | of_node_put(parent); | ||
431 | if (!OF_CHECK_COUNTS(na, ns)) | ||
432 | return NULL; | ||
433 | |||
434 | /* Get "reg" or "assigned-addresses" property */ | ||
435 | prop = (u32 *)get_property(dev, bus->addresses, &psize); | ||
436 | if (prop == NULL) | ||
437 | return NULL; | ||
438 | psize /= 4; | ||
439 | |||
440 | onesize = na + ns; | ||
441 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
442 | if (i == index) { | ||
443 | if (size) | ||
444 | *size = of_read_addr(prop + na, ns); | ||
445 | if (flags) | ||
446 | *flags = bus->get_flags(prop); | ||
447 | return prop; | ||
448 | } | ||
449 | return NULL; | ||
450 | } | ||
451 | EXPORT_SYMBOL(of_get_address); | ||
452 | |||
453 | u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
454 | unsigned int *flags) | ||
455 | { | ||
456 | u32 *prop; | ||
457 | unsigned int psize; | ||
458 | struct device_node *parent; | ||
459 | struct of_bus *bus; | ||
460 | int onesize, i, na, ns; | ||
461 | |||
462 | /* Get parent & match bus type */ | ||
463 | parent = of_get_parent(dev); | ||
464 | if (parent == NULL) | ||
465 | return NULL; | ||
466 | bus = of_match_bus(parent); | ||
467 | if (strcmp(bus->name, "pci")) | ||
468 | return NULL; | ||
469 | bus->count_cells(dev, &na, &ns); | ||
470 | of_node_put(parent); | ||
471 | if (!OF_CHECK_COUNTS(na, ns)) | ||
472 | return NULL; | ||
473 | |||
474 | /* Get "reg" or "assigned-addresses" property */ | ||
475 | prop = (u32 *)get_property(dev, bus->addresses, &psize); | ||
476 | if (prop == NULL) | ||
477 | return NULL; | ||
478 | psize /= 4; | ||
479 | |||
480 | onesize = na + ns; | ||
481 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
482 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
483 | if (size) | ||
484 | *size = of_read_addr(prop + na, ns); | ||
485 | if (flags) | ||
486 | *flags = bus->get_flags(prop); | ||
487 | return prop; | ||
488 | } | ||
489 | return NULL; | ||
490 | } | ||
491 | EXPORT_SYMBOL(of_get_pci_address); | ||
492 | |||
493 | static int __of_address_to_resource(struct device_node *dev, u32 *addrp, | ||
494 | u64 size, unsigned int flags, | ||
495 | struct resource *r) | ||
496 | { | ||
497 | u64 taddr; | ||
498 | |||
499 | if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) | ||
500 | return -EINVAL; | ||
501 | taddr = of_translate_address(dev, addrp); | ||
502 | if (taddr == OF_BAD_ADDR) | ||
503 | return -EINVAL; | ||
504 | memset(r, 0, sizeof(struct resource)); | ||
505 | if (flags & IORESOURCE_IO) { | ||
506 | unsigned long port; | ||
507 | port = pci_address_to_pio(taddr); | ||
508 | if (port == (unsigned long)-1) | ||
509 | return -EINVAL; | ||
510 | r->start = port; | ||
511 | r->end = port + size - 1; | ||
512 | } else { | ||
513 | r->start = taddr; | ||
514 | r->end = taddr + size - 1; | ||
515 | } | ||
516 | r->flags = flags; | ||
517 | r->name = dev->name; | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int of_address_to_resource(struct device_node *dev, int index, | ||
522 | struct resource *r) | ||
523 | { | ||
524 | u32 *addrp; | ||
525 | u64 size; | ||
526 | unsigned int flags; | ||
527 | |||
528 | addrp = of_get_address(dev, index, &size, &flags); | ||
529 | if (addrp == NULL) | ||
530 | return -EINVAL; | ||
531 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
532 | } | ||
533 | EXPORT_SYMBOL_GPL(of_address_to_resource); | ||
534 | |||
535 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
536 | struct resource *r) | ||
537 | { | ||
538 | u32 *addrp; | ||
539 | u64 size; | ||
540 | unsigned int flags; | ||
541 | |||
542 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
543 | if (addrp == NULL) | ||
544 | return -EINVAL; | ||
545 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
546 | } | ||
547 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 60dec2401c26..45b8109951fe 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -188,39 +188,19 @@ int is_python(struct device_node *dev) | |||
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | static int get_phb_reg_prop(struct device_node *dev, | 191 | static void python_countermeasures(struct device_node *dev) |
192 | unsigned int addr_size_words, | ||
193 | struct reg_property64 *reg) | ||
194 | { | 192 | { |
195 | unsigned int *ui_ptr = NULL, len; | 193 | struct resource registers; |
196 | |||
197 | /* Found a PHB, now figure out where his registers are mapped. */ | ||
198 | ui_ptr = (unsigned int *)get_property(dev, "reg", &len); | ||
199 | if (ui_ptr == NULL) | ||
200 | return 1; | ||
201 | |||
202 | if (addr_size_words == 1) { | ||
203 | reg->address = ((struct reg_property32 *)ui_ptr)->address; | ||
204 | reg->size = ((struct reg_property32 *)ui_ptr)->size; | ||
205 | } else { | ||
206 | *reg = *((struct reg_property64 *)ui_ptr); | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void python_countermeasures(struct device_node *dev, | ||
213 | unsigned int addr_size_words) | ||
214 | { | ||
215 | struct reg_property64 reg_struct; | ||
216 | void __iomem *chip_regs; | 194 | void __iomem *chip_regs; |
217 | volatile u32 val; | 195 | volatile u32 val; |
218 | 196 | ||
219 | if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) | 197 | if (of_address_to_resource(dev, 0, ®isters)) { |
198 | printk(KERN_ERR "Can't get address for Python workarounds !\n"); | ||
220 | return; | 199 | return; |
200 | } | ||
221 | 201 | ||
222 | /* Python's register file is 1 MB in size. */ | 202 | /* Python's register file is 1 MB in size. */ |
223 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); | 203 | chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000); |
224 | 204 | ||
225 | /* | 205 | /* |
226 | * Firmware doesn't always clear this bit which is critical | 206 | * Firmware doesn't always clear this bit which is critical |
@@ -301,11 +281,10 @@ static int phb_set_bus_ranges(struct device_node *dev, | |||
301 | } | 281 | } |
302 | 282 | ||
303 | static int __devinit setup_phb(struct device_node *dev, | 283 | static int __devinit setup_phb(struct device_node *dev, |
304 | struct pci_controller *phb, | 284 | struct pci_controller *phb) |
305 | unsigned int addr_size_words) | ||
306 | { | 285 | { |
307 | if (is_python(dev)) | 286 | if (is_python(dev)) |
308 | python_countermeasures(dev, addr_size_words); | 287 | python_countermeasures(dev); |
309 | 288 | ||
310 | if (phb_set_bus_ranges(dev, phb)) | 289 | if (phb_set_bus_ranges(dev, phb)) |
311 | return 1; | 290 | return 1; |
@@ -320,8 +299,8 @@ unsigned long __init find_and_init_phbs(void) | |||
320 | { | 299 | { |
321 | struct device_node *node; | 300 | struct device_node *node; |
322 | struct pci_controller *phb; | 301 | struct pci_controller *phb; |
323 | unsigned int root_size_cells = 0; | ||
324 | unsigned int index; | 302 | unsigned int index; |
303 | unsigned int root_size_cells = 0; | ||
325 | unsigned int *opprop = NULL; | 304 | unsigned int *opprop = NULL; |
326 | struct device_node *root = of_find_node_by_path("/"); | 305 | struct device_node *root = of_find_node_by_path("/"); |
327 | 306 | ||
@@ -343,10 +322,11 @@ unsigned long __init find_and_init_phbs(void) | |||
343 | phb = pcibios_alloc_controller(node); | 322 | phb = pcibios_alloc_controller(node); |
344 | if (!phb) | 323 | if (!phb) |
345 | continue; | 324 | continue; |
346 | setup_phb(node, phb, root_size_cells); | 325 | setup_phb(node, phb); |
347 | pci_process_bridge_OF_ranges(phb, node, 0); | 326 | pci_process_bridge_OF_ranges(phb, node, 0); |
348 | pci_setup_phb_io(phb, index == 0); | 327 | pci_setup_phb_io(phb, index == 0); |
349 | #ifdef CONFIG_PPC_PSERIES | 328 | #ifdef CONFIG_PPC_PSERIES |
329 | /* XXX This code need serious fixing ... --BenH */ | ||
350 | if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { | 330 | if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { |
351 | int addr = root_size_cells * (index + 2) - 1; | 331 | int addr = root_size_cells * (index + 2) - 1; |
352 | mpic_assign_isu(pSeries_mpic, index, opprop[addr]); | 332 | mpic_assign_isu(pSeries_mpic, index, opprop[addr]); |
@@ -381,22 +361,17 @@ unsigned long __init find_and_init_phbs(void) | |||
381 | 361 | ||
382 | struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | 362 | struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) |
383 | { | 363 | { |
384 | struct device_node *root = of_find_node_by_path("/"); | ||
385 | unsigned int root_size_cells = 0; | ||
386 | struct pci_controller *phb; | 364 | struct pci_controller *phb; |
387 | int primary; | 365 | int primary; |
388 | 366 | ||
389 | root_size_cells = prom_n_size_cells(root); | ||
390 | |||
391 | primary = list_empty(&hose_list); | 367 | primary = list_empty(&hose_list); |
392 | phb = pcibios_alloc_controller(dn); | 368 | phb = pcibios_alloc_controller(dn); |
393 | if (!phb) | 369 | if (!phb) |
394 | return NULL; | 370 | return NULL; |
395 | setup_phb(dn, phb, root_size_cells); | 371 | setup_phb(dn, phb); |
396 | pci_process_bridge_OF_ranges(phb, dn, primary); | 372 | pci_process_bridge_OF_ranges(phb, dn, primary); |
397 | 373 | ||
398 | pci_setup_phb_io_dynamic(phb, primary); | 374 | pci_setup_phb_io_dynamic(phb, primary); |
399 | of_node_put(root); | ||
400 | 375 | ||
401 | pci_devs_phb_init_dynamic(phb); | 376 | pci_devs_phb_init_dynamic(phb); |
402 | scan_phb(phb); | 377 | scan_phb(phb); |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index bd3eb4292b53..d5c52fae023a 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -93,8 +93,8 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs); | |||
93 | /* also used by kexec */ | 93 | /* also used by kexec */ |
94 | void machine_shutdown(void) | 94 | void machine_shutdown(void) |
95 | { | 95 | { |
96 | if (ppc_md.nvram_sync) | 96 | if (ppc_md.machine_shutdown) |
97 | ppc_md.nvram_sync(); | 97 | ppc_md.machine_shutdown(); |
98 | } | 98 | } |
99 | 99 | ||
100 | void machine_restart(char *cmd) | 100 | void machine_restart(char *cmd) |
@@ -294,129 +294,6 @@ struct seq_operations cpuinfo_op = { | |||
294 | .show = show_cpuinfo, | 294 | .show = show_cpuinfo, |
295 | }; | 295 | }; |
296 | 296 | ||
297 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
298 | static int __init set_preferred_console(void) | ||
299 | { | ||
300 | struct device_node *prom_stdout = NULL; | ||
301 | char *name; | ||
302 | u32 *spd; | ||
303 | int offset = 0; | ||
304 | |||
305 | DBG(" -> set_preferred_console()\n"); | ||
306 | |||
307 | /* The user has requested a console so this is already set up. */ | ||
308 | if (strstr(saved_command_line, "console=")) { | ||
309 | DBG(" console was specified !\n"); | ||
310 | return -EBUSY; | ||
311 | } | ||
312 | |||
313 | if (!of_chosen) { | ||
314 | DBG(" of_chosen is NULL !\n"); | ||
315 | return -ENODEV; | ||
316 | } | ||
317 | /* We are getting a weird phandle from OF ... */ | ||
318 | /* ... So use the full path instead */ | ||
319 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | ||
320 | if (name == NULL) { | ||
321 | DBG(" no linux,stdout-path !\n"); | ||
322 | return -ENODEV; | ||
323 | } | ||
324 | prom_stdout = of_find_node_by_path(name); | ||
325 | if (!prom_stdout) { | ||
326 | DBG(" can't find stdout package %s !\n", name); | ||
327 | return -ENODEV; | ||
328 | } | ||
329 | DBG("stdout is %s\n", prom_stdout->full_name); | ||
330 | |||
331 | name = (char *)get_property(prom_stdout, "name", NULL); | ||
332 | if (!name) { | ||
333 | DBG(" stdout package has no name !\n"); | ||
334 | goto not_found; | ||
335 | } | ||
336 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); | ||
337 | |||
338 | if (0) | ||
339 | ; | ||
340 | #ifdef CONFIG_SERIAL_8250_CONSOLE | ||
341 | else if (strcmp(name, "serial") == 0) { | ||
342 | int i; | ||
343 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); | ||
344 | if (i > 8) { | ||
345 | switch (reg[1]) { | ||
346 | case 0x3f8: | ||
347 | offset = 0; | ||
348 | break; | ||
349 | case 0x2f8: | ||
350 | offset = 1; | ||
351 | break; | ||
352 | case 0x898: | ||
353 | offset = 2; | ||
354 | break; | ||
355 | case 0x890: | ||
356 | offset = 3; | ||
357 | break; | ||
358 | default: | ||
359 | /* We dont recognise the serial port */ | ||
360 | goto not_found; | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | ||
365 | #ifdef CONFIG_PPC_PSERIES | ||
366 | else if (strcmp(name, "vty") == 0) { | ||
367 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); | ||
368 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); | ||
369 | |||
370 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { | ||
371 | /* Host Virtual Serial Interface */ | ||
372 | switch (reg[0]) { | ||
373 | case 0x30000000: | ||
374 | offset = 0; | ||
375 | break; | ||
376 | case 0x30000001: | ||
377 | offset = 1; | ||
378 | break; | ||
379 | default: | ||
380 | goto not_found; | ||
381 | } | ||
382 | of_node_put(prom_stdout); | ||
383 | DBG("Found hvsi console at offset %d\n", offset); | ||
384 | return add_preferred_console("hvsi", offset, NULL); | ||
385 | } else { | ||
386 | /* pSeries LPAR virtual console */ | ||
387 | of_node_put(prom_stdout); | ||
388 | DBG("Found hvc console\n"); | ||
389 | return add_preferred_console("hvc", 0, NULL); | ||
390 | } | ||
391 | } | ||
392 | #endif /* CONFIG_PPC_PSERIES */ | ||
393 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | ||
394 | else if (strcmp(name, "ch-a") == 0) | ||
395 | offset = 0; | ||
396 | else if (strcmp(name, "ch-b") == 0) | ||
397 | offset = 1; | ||
398 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | ||
399 | else | ||
400 | goto not_found; | ||
401 | of_node_put(prom_stdout); | ||
402 | |||
403 | DBG("Found serial console at ttyS%d\n", offset); | ||
404 | |||
405 | if (spd) { | ||
406 | static char __initdata opt[16]; | ||
407 | sprintf(opt, "%d", *spd); | ||
408 | return add_preferred_console("ttyS", offset, opt); | ||
409 | } else | ||
410 | return add_preferred_console("ttyS", offset, NULL); | ||
411 | |||
412 | not_found: | ||
413 | DBG("No preferred console found !\n"); | ||
414 | of_node_put(prom_stdout); | ||
415 | return -ENODEV; | ||
416 | } | ||
417 | console_initcall(set_preferred_console); | ||
418 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
419 | |||
420 | void __init check_for_initrd(void) | 297 | void __init check_for_initrd(void) |
421 | { | 298 | { |
422 | #ifdef CONFIG_BLK_DEV_INITRD | 299 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -442,7 +319,7 @@ void __init check_for_initrd(void) | |||
442 | /* If we were passed an initrd, set the ROOT_DEV properly if the values | 319 | /* If we were passed an initrd, set the ROOT_DEV properly if the values |
443 | * look sensible. If not, clear initrd reference. | 320 | * look sensible. If not, clear initrd reference. |
444 | */ | 321 | */ |
445 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && | 322 | if (is_kernel_addr(initrd_start) && is_kernel_addr(initrd_end) && |
446 | initrd_end > initrd_start) | 323 | initrd_end > initrd_start) |
447 | ROOT_DEV = Root_RAM0; | 324 | ROOT_DEV = Root_RAM0; |
448 | else | 325 | else |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index e5694335bf10..e5d285adb496 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <asm/nvram.h> | 39 | #include <asm/nvram.h> |
40 | #include <asm/xmon.h> | 40 | #include <asm/xmon.h> |
41 | #include <asm/time.h> | 41 | #include <asm/time.h> |
42 | #include <asm/serial.h> | ||
43 | #include <asm/udbg.h> | ||
42 | 44 | ||
43 | #include "setup.h" | 45 | #include "setup.h" |
44 | 46 | ||
@@ -172,12 +174,23 @@ void __init platform_init(void) | |||
172 | */ | 174 | */ |
173 | void __init machine_init(unsigned long dt_ptr, unsigned long phys) | 175 | void __init machine_init(unsigned long dt_ptr, unsigned long phys) |
174 | { | 176 | { |
177 | /* If btext is enabled, we might have a BAT setup for early display, | ||
178 | * thus we do enable some very basic udbg output | ||
179 | */ | ||
180 | #ifdef CONFIG_BOOTX_TEXT | ||
181 | udbg_putc = btext_drawchar; | ||
182 | #endif | ||
183 | |||
184 | /* Do some early initialization based on the flat device tree */ | ||
175 | early_init_devtree(__va(dt_ptr)); | 185 | early_init_devtree(__va(dt_ptr)); |
176 | 186 | ||
187 | /* Check default command line */ | ||
177 | #ifdef CONFIG_CMDLINE | 188 | #ifdef CONFIG_CMDLINE |
178 | strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); | 189 | if (cmd_line[0] == 0) |
190 | strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); | ||
179 | #endif /* CONFIG_CMDLINE */ | 191 | #endif /* CONFIG_CMDLINE */ |
180 | 192 | ||
193 | /* Base init based on machine type */ | ||
181 | platform_init(); | 194 | platform_init(); |
182 | 195 | ||
183 | #ifdef CONFIG_6xx | 196 | #ifdef CONFIG_6xx |
@@ -282,25 +295,22 @@ void __init setup_arch(char **cmdline_p) | |||
282 | 295 | ||
283 | unflatten_device_tree(); | 296 | unflatten_device_tree(); |
284 | check_for_initrd(); | 297 | check_for_initrd(); |
285 | finish_device_tree(); | ||
286 | 298 | ||
287 | smp_setup_cpu_maps(); | 299 | if (ppc_md.init_early) |
300 | ppc_md.init_early(); | ||
288 | 301 | ||
289 | #ifdef CONFIG_BOOTX_TEXT | 302 | #ifdef CONFIG_SERIAL_8250 |
290 | init_boot_display(); | 303 | find_legacy_serial_ports(); |
291 | #endif | 304 | #endif |
305 | finish_device_tree(); | ||
292 | 306 | ||
293 | #ifdef CONFIG_PPC_PMAC | 307 | smp_setup_cpu_maps(); |
294 | /* This could be called "early setup arch", it must be done | ||
295 | * now because xmon need it | ||
296 | */ | ||
297 | if (_machine == _MACH_Pmac) | ||
298 | pmac_feature_init(); /* New cool way */ | ||
299 | #endif | ||
300 | 308 | ||
301 | #ifdef CONFIG_XMON_DEFAULT | 309 | #ifdef CONFIG_XMON_DEFAULT |
302 | xmon_init(1); | 310 | xmon_init(1); |
303 | #endif | 311 | #endif |
312 | /* Register early console */ | ||
313 | register_early_udbg_console(); | ||
304 | 314 | ||
305 | #if defined(CONFIG_KGDB) | 315 | #if defined(CONFIG_KGDB) |
306 | if (ppc_md.kgdb_map_scc) | 316 | if (ppc_md.kgdb_map_scc) |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e3fb78397dc6..98e9f0595dd8 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/serial.h> | 34 | #include <linux/serial.h> |
35 | #include <linux/serial_8250.h> | 35 | #include <linux/serial_8250.h> |
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
37 | #include <asm/kdump.h> | ||
37 | #include <asm/prom.h> | 38 | #include <asm/prom.h> |
38 | #include <asm/processor.h> | 39 | #include <asm/processor.h> |
39 | #include <asm/pgtable.h> | 40 | #include <asm/pgtable.h> |
@@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr) | |||
268 | } | 269 | } |
269 | ppc_md = **mach; | 270 | ppc_md = **mach; |
270 | 271 | ||
272 | #ifdef CONFIG_CRASH_DUMP | ||
273 | kdump_setup(); | ||
274 | #endif | ||
275 | |||
271 | DBG("Found, Initializing memory management...\n"); | 276 | DBG("Found, Initializing memory management...\n"); |
272 | 277 | ||
273 | /* | 278 | /* |
@@ -317,6 +322,7 @@ void early_setup_secondary(void) | |||
317 | void smp_release_cpus(void) | 322 | void smp_release_cpus(void) |
318 | { | 323 | { |
319 | extern unsigned long __secondary_hold_spinloop; | 324 | extern unsigned long __secondary_hold_spinloop; |
325 | unsigned long *ptr; | ||
320 | 326 | ||
321 | DBG(" -> smp_release_cpus()\n"); | 327 | DBG(" -> smp_release_cpus()\n"); |
322 | 328 | ||
@@ -327,7 +333,9 @@ void smp_release_cpus(void) | |||
327 | * This is useless but harmless on iSeries, secondaries are already | 333 | * This is useless but harmless on iSeries, secondaries are already |
328 | * waiting on their paca spinloops. */ | 334 | * waiting on their paca spinloops. */ |
329 | 335 | ||
330 | __secondary_hold_spinloop = 1; | 336 | ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop |
337 | - PHYSICAL_START); | ||
338 | *ptr = 1; | ||
331 | mb(); | 339 | mb(); |
332 | 340 | ||
333 | DBG(" <- smp_release_cpus()\n"); | 341 | DBG(" <- smp_release_cpus()\n"); |
@@ -459,16 +467,21 @@ void __init setup_system(void) | |||
459 | */ | 467 | */ |
460 | ppc_md.init_early(); | 468 | ppc_md.init_early(); |
461 | 469 | ||
470 | /* | ||
471 | * We can discover serial ports now since the above did setup the | ||
472 | * hash table management for us, thus ioremap works. We do that early | ||
473 | * so that further code can be debugged | ||
474 | */ | ||
475 | #ifdef CONFIG_SERIAL_8250 | ||
476 | find_legacy_serial_ports(); | ||
477 | #endif | ||
478 | |||
462 | /* | 479 | /* |
463 | * "Finish" the device-tree, that is do the actual parsing of | 480 | * "Finish" the device-tree, that is do the actual parsing of |
464 | * some of the properties like the interrupt map | 481 | * some of the properties like the interrupt map |
465 | */ | 482 | */ |
466 | finish_device_tree(); | 483 | finish_device_tree(); |
467 | 484 | ||
468 | #ifdef CONFIG_BOOTX_TEXT | ||
469 | init_boot_display(); | ||
470 | #endif | ||
471 | |||
472 | /* | 485 | /* |
473 | * Initialize xmon | 486 | * Initialize xmon |
474 | */ | 487 | */ |
@@ -507,6 +520,9 @@ void __init setup_system(void) | |||
507 | ppc64_caches.iline_size); | 520 | ppc64_caches.iline_size); |
508 | printk("htab_address = 0x%p\n", htab_address); | 521 | printk("htab_address = 0x%p\n", htab_address); |
509 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); | 522 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); |
523 | #if PHYSICAL_START > 0 | ||
524 | printk("physical_start = 0x%x\n", PHYSICAL_START); | ||
525 | #endif | ||
510 | printk("-----------------------------------------------------\n"); | 526 | printk("-----------------------------------------------------\n"); |
511 | 527 | ||
512 | mm_init_ppc64(); | 528 | mm_init_ppc64(); |
@@ -657,187 +673,6 @@ void ppc64_terminate_msg(unsigned int src, const char *msg) | |||
657 | printk("[terminate]%04x %s\n", src, msg); | 673 | printk("[terminate]%04x %s\n", src, msg); |
658 | } | 674 | } |
659 | 675 | ||
660 | #ifndef CONFIG_PPC_ISERIES | ||
661 | /* | ||
662 | * This function can be used by platforms to "find" legacy serial ports. | ||
663 | * It works for "serial" nodes under an "isa" node, and will try to | ||
664 | * respect the "ibm,aix-loc" property if any. It works with up to 8 | ||
665 | * ports. | ||
666 | */ | ||
667 | |||
668 | #define MAX_LEGACY_SERIAL_PORTS 8 | ||
669 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | ||
670 | static unsigned int old_serial_count; | ||
671 | |||
672 | void __init generic_find_legacy_serial_ports(u64 *physport, | ||
673 | unsigned int *default_speed) | ||
674 | { | ||
675 | struct device_node *np; | ||
676 | u32 *sizeprop; | ||
677 | |||
678 | struct isa_reg_property { | ||
679 | u32 space; | ||
680 | u32 address; | ||
681 | u32 size; | ||
682 | }; | ||
683 | struct pci_reg_property { | ||
684 | struct pci_address addr; | ||
685 | u32 size_hi; | ||
686 | u32 size_lo; | ||
687 | }; | ||
688 | |||
689 | DBG(" -> generic_find_legacy_serial_port()\n"); | ||
690 | |||
691 | *physport = 0; | ||
692 | if (default_speed) | ||
693 | *default_speed = 0; | ||
694 | |||
695 | np = of_find_node_by_path("/"); | ||
696 | if (!np) | ||
697 | return; | ||
698 | |||
699 | /* First fill our array */ | ||
700 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | ||
701 | struct device_node *isa, *pci; | ||
702 | struct isa_reg_property *reg; | ||
703 | unsigned long phys_size, addr_size, io_base; | ||
704 | u32 *rangesp; | ||
705 | u32 *interrupts, *clk, *spd; | ||
706 | char *typep; | ||
707 | int index, rlen, rentsize; | ||
708 | |||
709 | /* Ok, first check if it's under an "isa" parent */ | ||
710 | isa = of_get_parent(np); | ||
711 | if (!isa || strcmp(isa->name, "isa")) { | ||
712 | DBG("%s: no isa parent found\n", np->full_name); | ||
713 | continue; | ||
714 | } | ||
715 | |||
716 | /* Now look for an "ibm,aix-loc" property that gives us ordering | ||
717 | * if any... | ||
718 | */ | ||
719 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | ||
720 | |||
721 | /* Get the ISA port number */ | ||
722 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); | ||
723 | if (reg == NULL) | ||
724 | goto next_port; | ||
725 | /* We assume the interrupt number isn't translated ... */ | ||
726 | interrupts = (u32 *)get_property(np, "interrupts", NULL); | ||
727 | /* get clock freq. if present */ | ||
728 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | ||
729 | /* get default speed if present */ | ||
730 | spd = (u32 *)get_property(np, "current-speed", NULL); | ||
731 | /* Default to locate at end of array */ | ||
732 | index = old_serial_count; /* end of the array by default */ | ||
733 | |||
734 | /* If we have a location index, then use it */ | ||
735 | if (typep && *typep == 'S') { | ||
736 | index = simple_strtol(typep+1, NULL, 0) - 1; | ||
737 | /* if index is out of range, use end of array instead */ | ||
738 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
739 | index = old_serial_count; | ||
740 | /* if our index is still out of range, that mean that | ||
741 | * array is full, we could scan for a free slot but that | ||
742 | * make little sense to bother, just skip the port | ||
743 | */ | ||
744 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
745 | goto next_port; | ||
746 | if (index >= old_serial_count) | ||
747 | old_serial_count = index + 1; | ||
748 | /* Check if there is a port who already claimed our slot */ | ||
749 | if (serial_ports[index].iobase != 0) { | ||
750 | /* if we still have some room, move it, else override */ | ||
751 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { | ||
752 | DBG("Moved legacy port %d -> %d\n", index, | ||
753 | old_serial_count); | ||
754 | serial_ports[old_serial_count++] = | ||
755 | serial_ports[index]; | ||
756 | } else { | ||
757 | DBG("Replacing legacy port %d\n", index); | ||
758 | } | ||
759 | } | ||
760 | } | ||
761 | if (index >= MAX_LEGACY_SERIAL_PORTS) | ||
762 | goto next_port; | ||
763 | if (index >= old_serial_count) | ||
764 | old_serial_count = index + 1; | ||
765 | |||
766 | /* Now fill the entry */ | ||
767 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); | ||
768 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; | ||
769 | serial_ports[index].iobase = reg->address; | ||
770 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; | ||
771 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; | ||
772 | |||
773 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", | ||
774 | index, | ||
775 | serial_ports[index].iobase, | ||
776 | serial_ports[index].irq, | ||
777 | serial_ports[index].uartclk); | ||
778 | |||
779 | /* Get phys address of IO reg for port 1 */ | ||
780 | if (index != 0) | ||
781 | goto next_port; | ||
782 | |||
783 | pci = of_get_parent(isa); | ||
784 | if (!pci) { | ||
785 | DBG("%s: no pci parent found\n", np->full_name); | ||
786 | goto next_port; | ||
787 | } | ||
788 | |||
789 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); | ||
790 | if (rangesp == NULL) { | ||
791 | of_node_put(pci); | ||
792 | goto next_port; | ||
793 | } | ||
794 | rlen /= 4; | ||
795 | |||
796 | /* we need the #size-cells of the PCI bridge node itself */ | ||
797 | phys_size = 1; | ||
798 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); | ||
799 | if (sizeprop != NULL) | ||
800 | phys_size = *sizeprop; | ||
801 | /* we need the parent #addr-cells */ | ||
802 | addr_size = prom_n_addr_cells(pci); | ||
803 | rentsize = 3 + addr_size + phys_size; | ||
804 | io_base = 0; | ||
805 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { | ||
806 | if (((rangesp[0] >> 24) & 0x3) != 1) | ||
807 | continue; /* not IO space */ | ||
808 | io_base = rangesp[3]; | ||
809 | if (addr_size == 2) | ||
810 | io_base = (io_base << 32) | rangesp[4]; | ||
811 | } | ||
812 | if (io_base != 0) { | ||
813 | *physport = io_base + reg->address; | ||
814 | if (default_speed && spd) | ||
815 | *default_speed = *spd; | ||
816 | } | ||
817 | of_node_put(pci); | ||
818 | next_port: | ||
819 | of_node_put(isa); | ||
820 | } | ||
821 | |||
822 | DBG(" <- generic_find_legacy_serial_port()\n"); | ||
823 | } | ||
824 | |||
825 | static struct platform_device serial_device = { | ||
826 | .name = "serial8250", | ||
827 | .id = PLAT8250_DEV_PLATFORM, | ||
828 | .dev = { | ||
829 | .platform_data = serial_ports, | ||
830 | }, | ||
831 | }; | ||
832 | |||
833 | static int __init serial_dev_init(void) | ||
834 | { | ||
835 | return platform_device_register(&serial_device); | ||
836 | } | ||
837 | arch_initcall(serial_dev_init); | ||
838 | |||
839 | #endif /* CONFIG_PPC_ISERIES */ | ||
840 | |||
841 | int check_legacy_ioport(unsigned long base_port) | 676 | int check_legacy_ioport(unsigned long base_port) |
842 | { | 677 | { |
843 | if (ppc_md.check_legacy_ioport == NULL) | 678 | if (ppc_md.check_legacy_ioport == NULL) |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 5a2eba60dd39..d3f0b6d452fb 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -76,7 +76,6 @@ | |||
76 | * registers from *regs. This is what we need | 76 | * registers from *regs. This is what we need |
77 | * to do when a signal has been delivered. | 77 | * to do when a signal has been delivered. |
78 | */ | 78 | */ |
79 | #define sigreturn_exit(regs) return 0 | ||
80 | 79 | ||
81 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) | 80 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) |
82 | #undef __SIGNAL_FRAMESIZE | 81 | #undef __SIGNAL_FRAMESIZE |
@@ -156,9 +155,17 @@ static inline int save_general_regs(struct pt_regs *regs, | |||
156 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; | 155 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; |
157 | int i; | 156 | int i; |
158 | 157 | ||
159 | for (i = 0; i <= PT_RESULT; i ++) | 158 | if (!FULL_REGS(regs)) { |
159 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
160 | current_thread_info()->nvgprs_frame = frame->mc_gregs; | ||
161 | } | ||
162 | |||
163 | for (i = 0; i <= PT_RESULT; i ++) { | ||
164 | if (i == 14 && !FULL_REGS(regs)) | ||
165 | i = 32; | ||
160 | if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) | 166 | if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) |
161 | return -EFAULT; | 167 | return -EFAULT; |
168 | } | ||
162 | return 0; | 169 | return 0; |
163 | } | 170 | } |
164 | 171 | ||
@@ -179,8 +186,6 @@ static inline int restore_general_regs(struct pt_regs *regs, | |||
179 | 186 | ||
180 | #else /* CONFIG_PPC64 */ | 187 | #else /* CONFIG_PPC64 */ |
181 | 188 | ||
182 | extern void sigreturn_exit(struct pt_regs *); | ||
183 | |||
184 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) | 189 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) |
185 | 190 | ||
186 | static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) | 191 | static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) |
@@ -214,6 +219,15 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka, | |||
214 | static inline int save_general_regs(struct pt_regs *regs, | 219 | static inline int save_general_regs(struct pt_regs *regs, |
215 | struct mcontext __user *frame) | 220 | struct mcontext __user *frame) |
216 | { | 221 | { |
222 | if (!FULL_REGS(regs)) { | ||
223 | /* Zero out the unsaved GPRs to avoid information | ||
224 | leak, and set TIF_SAVE_NVGPRS to ensure that the | ||
225 | registers do actually get saved later. */ | ||
226 | memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); | ||
227 | current_thread_info()->nvgprs_frame = &frame->mc_gregs; | ||
228 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
229 | } | ||
230 | |||
217 | return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); | 231 | return __copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE); |
218 | } | 232 | } |
219 | 233 | ||
@@ -256,8 +270,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, | |||
256 | while (1) { | 270 | while (1) { |
257 | current->state = TASK_INTERRUPTIBLE; | 271 | current->state = TASK_INTERRUPTIBLE; |
258 | schedule(); | 272 | schedule(); |
259 | if (do_signal(&saveset, regs)) | 273 | if (do_signal(&saveset, regs)) { |
260 | sigreturn_exit(regs); | 274 | set_thread_flag(TIF_RESTOREALL); |
275 | return 0; | ||
276 | } | ||
261 | } | 277 | } |
262 | } | 278 | } |
263 | 279 | ||
@@ -292,8 +308,10 @@ long sys_rt_sigsuspend( | |||
292 | while (1) { | 308 | while (1) { |
293 | current->state = TASK_INTERRUPTIBLE; | 309 | current->state = TASK_INTERRUPTIBLE; |
294 | schedule(); | 310 | schedule(); |
295 | if (do_signal(&saveset, regs)) | 311 | if (do_signal(&saveset, regs)) { |
296 | sigreturn_exit(regs); | 312 | set_thread_flag(TIF_RESTOREALL); |
313 | return 0; | ||
314 | } | ||
297 | } | 315 | } |
298 | } | 316 | } |
299 | 317 | ||
@@ -391,9 +409,6 @@ struct rt_sigframe { | |||
391 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | 409 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, |
392 | int sigret) | 410 | int sigret) |
393 | { | 411 | { |
394 | #ifdef CONFIG_PPC32 | ||
395 | CHECK_FULL_REGS(regs); | ||
396 | #endif | ||
397 | /* Make sure floating point registers are stored in regs */ | 412 | /* Make sure floating point registers are stored in regs */ |
398 | flush_fp_to_thread(current); | 413 | flush_fp_to_thread(current); |
399 | 414 | ||
@@ -828,12 +843,6 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, | |||
828 | regs->gpr[6] = (unsigned long) rt_sf; | 843 | regs->gpr[6] = (unsigned long) rt_sf; |
829 | regs->nip = (unsigned long) ka->sa.sa_handler; | 844 | regs->nip = (unsigned long) ka->sa.sa_handler; |
830 | regs->trap = 0; | 845 | regs->trap = 0; |
831 | #ifdef CONFIG_PPC64 | ||
832 | regs->result = 0; | ||
833 | |||
834 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
835 | ptrace_notify(SIGTRAP); | ||
836 | #endif | ||
837 | return 1; | 846 | return 1; |
838 | 847 | ||
839 | badframe: | 848 | badframe: |
@@ -911,8 +920,8 @@ long sys_swapcontext(struct ucontext __user *old_ctx, | |||
911 | */ | 920 | */ |
912 | if (do_setcontext(new_ctx, regs, 0)) | 921 | if (do_setcontext(new_ctx, regs, 0)) |
913 | do_exit(SIGSEGV); | 922 | do_exit(SIGSEGV); |
914 | sigreturn_exit(regs); | 923 | |
915 | /* doesn't actually return back to here */ | 924 | set_thread_flag(TIF_RESTOREALL); |
916 | return 0; | 925 | return 0; |
917 | } | 926 | } |
918 | 927 | ||
@@ -945,12 +954,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, | |||
945 | * nobody does any... | 954 | * nobody does any... |
946 | */ | 955 | */ |
947 | compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); | 956 | compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); |
948 | return (int)regs->result; | ||
949 | #else | 957 | #else |
950 | do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); | 958 | do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); |
951 | sigreturn_exit(regs); /* doesn't return here */ | ||
952 | return 0; | ||
953 | #endif | 959 | #endif |
960 | set_thread_flag(TIF_RESTOREALL); | ||
961 | return 0; | ||
954 | 962 | ||
955 | bad: | 963 | bad: |
956 | force_sig(SIGSEGV, current); | 964 | force_sig(SIGSEGV, current); |
@@ -1041,9 +1049,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx, | |||
1041 | */ | 1049 | */ |
1042 | do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); | 1050 | do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); |
1043 | 1051 | ||
1044 | sigreturn_exit(regs); | 1052 | set_thread_flag(TIF_RESTOREALL); |
1045 | /* doesn't actually return back to here */ | ||
1046 | |||
1047 | out: | 1053 | out: |
1048 | return 0; | 1054 | return 0; |
1049 | } | 1055 | } |
@@ -1107,12 +1113,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
1107 | regs->gpr[4] = (unsigned long) sc; | 1113 | regs->gpr[4] = (unsigned long) sc; |
1108 | regs->nip = (unsigned long) ka->sa.sa_handler; | 1114 | regs->nip = (unsigned long) ka->sa.sa_handler; |
1109 | regs->trap = 0; | 1115 | regs->trap = 0; |
1110 | #ifdef CONFIG_PPC64 | ||
1111 | regs->result = 0; | ||
1112 | |||
1113 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
1114 | ptrace_notify(SIGTRAP); | ||
1115 | #endif | ||
1116 | 1116 | ||
1117 | return 1; | 1117 | return 1; |
1118 | 1118 | ||
@@ -1160,12 +1160,8 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, | |||
1160 | || restore_user_regs(regs, sr, 1)) | 1160 | || restore_user_regs(regs, sr, 1)) |
1161 | goto badframe; | 1161 | goto badframe; |
1162 | 1162 | ||
1163 | #ifdef CONFIG_PPC64 | 1163 | set_thread_flag(TIF_RESTOREALL); |
1164 | return (int)regs->result; | ||
1165 | #else | ||
1166 | sigreturn_exit(regs); /* doesn't return */ | ||
1167 | return 0; | 1164 | return 0; |
1168 | #endif | ||
1169 | 1165 | ||
1170 | badframe: | 1166 | badframe: |
1171 | force_sig(SIGSEGV, current); | 1167 | force_sig(SIGSEGV, current); |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 1decf2785530..5462bef898f6 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -96,8 +96,10 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int | |||
96 | while (1) { | 96 | while (1) { |
97 | current->state = TASK_INTERRUPTIBLE; | 97 | current->state = TASK_INTERRUPTIBLE; |
98 | schedule(); | 98 | schedule(); |
99 | if (do_signal(&saveset, regs)) | 99 | if (do_signal(&saveset, regs)) { |
100 | set_thread_flag(TIF_RESTOREALL); | ||
100 | return 0; | 101 | return 0; |
102 | } | ||
101 | } | 103 | } |
102 | } | 104 | } |
103 | 105 | ||
@@ -152,6 +154,14 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
152 | err |= __put_user(0, &sc->v_regs); | 154 | err |= __put_user(0, &sc->v_regs); |
153 | #endif /* CONFIG_ALTIVEC */ | 155 | #endif /* CONFIG_ALTIVEC */ |
154 | err |= __put_user(&sc->gp_regs, &sc->regs); | 156 | err |= __put_user(&sc->gp_regs, &sc->regs); |
157 | if (!FULL_REGS(regs)) { | ||
158 | /* Zero out the unsaved GPRs to avoid information | ||
159 | leak, and set TIF_SAVE_NVGPRS to ensure that the | ||
160 | registers do actually get saved later. */ | ||
161 | memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); | ||
162 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
163 | current_thread_info()->nvgprs_frame = &sc->gp_regs; | ||
164 | } | ||
155 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); | 165 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); |
156 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); | 166 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); |
157 | err |= __put_user(signr, &sc->signal); | 167 | err |= __put_user(signr, &sc->signal); |
@@ -340,6 +350,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx, | |||
340 | do_exit(SIGSEGV); | 350 | do_exit(SIGSEGV); |
341 | 351 | ||
342 | /* This returns like rt_sigreturn */ | 352 | /* This returns like rt_sigreturn */ |
353 | set_thread_flag(TIF_RESTOREALL); | ||
343 | return 0; | 354 | return 0; |
344 | } | 355 | } |
345 | 356 | ||
@@ -372,7 +383,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, | |||
372 | */ | 383 | */ |
373 | do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); | 384 | do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); |
374 | 385 | ||
375 | return regs->result; | 386 | set_thread_flag(TIF_RESTOREALL); |
387 | return 0; | ||
376 | 388 | ||
377 | badframe: | 389 | badframe: |
378 | #if DEBUG_SIG | 390 | #if DEBUG_SIG |
@@ -454,9 +466,6 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
454 | if (err) | 466 | if (err) |
455 | goto badframe; | 467 | goto badframe; |
456 | 468 | ||
457 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
458 | ptrace_notify(SIGTRAP); | ||
459 | |||
460 | return 1; | 469 | return 1; |
461 | 470 | ||
462 | badframe: | 471 | badframe: |
@@ -502,6 +511,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | |||
502 | * we only get here if there is a handler, we dont restart. | 511 | * we only get here if there is a handler, we dont restart. |
503 | */ | 512 | */ |
504 | regs->result = -EINTR; | 513 | regs->result = -EINTR; |
514 | regs->gpr[3] = EINTR; | ||
515 | regs->ccr |= 0x10000000; | ||
505 | break; | 516 | break; |
506 | case -ERESTARTSYS: | 517 | case -ERESTARTSYS: |
507 | /* ERESTARTSYS means to restart the syscall if there is no | 518 | /* ERESTARTSYS means to restart the syscall if there is no |
@@ -509,6 +520,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | |||
509 | */ | 520 | */ |
510 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 521 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
511 | regs->result = -EINTR; | 522 | regs->result = -EINTR; |
523 | regs->gpr[3] = EINTR; | ||
524 | regs->ccr |= 0x10000000; | ||
512 | break; | 525 | break; |
513 | } | 526 | } |
514 | /* fallthrough */ | 527 | /* fallthrough */ |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 30374d2f88e5..d381ec90b759 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/sysdev.h> | 31 | #include <linux/sysdev.h> |
32 | #include <linux/cpu.h> | 32 | #include <linux/cpu.h> |
33 | #include <linux/notifier.h> | 33 | #include <linux/notifier.h> |
34 | #include <linux/topology.h> | ||
34 | 35 | ||
35 | #include <asm/ptrace.h> | 36 | #include <asm/ptrace.h> |
36 | #include <asm/atomic.h> | 37 | #include <asm/atomic.h> |
@@ -75,6 +76,8 @@ void smp_call_function_interrupt(void); | |||
75 | 76 | ||
76 | int smt_enabled_at_boot = 1; | 77 | int smt_enabled_at_boot = 1; |
77 | 78 | ||
79 | static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; | ||
80 | |||
78 | #ifdef CONFIG_MPIC | 81 | #ifdef CONFIG_MPIC |
79 | int __init smp_mpic_probe(void) | 82 | int __init smp_mpic_probe(void) |
80 | { | 83 | { |
@@ -123,11 +126,16 @@ void smp_message_recv(int msg, struct pt_regs *regs) | |||
123 | /* XXX Do we have to do this? */ | 126 | /* XXX Do we have to do this? */ |
124 | set_need_resched(); | 127 | set_need_resched(); |
125 | break; | 128 | break; |
126 | #ifdef CONFIG_DEBUGGER | ||
127 | case PPC_MSG_DEBUGGER_BREAK: | 129 | case PPC_MSG_DEBUGGER_BREAK: |
130 | if (crash_ipi_function_ptr) { | ||
131 | crash_ipi_function_ptr(regs); | ||
132 | break; | ||
133 | } | ||
134 | #ifdef CONFIG_DEBUGGER | ||
128 | debugger_ipi(regs); | 135 | debugger_ipi(regs); |
129 | break; | 136 | break; |
130 | #endif | 137 | #endif /* CONFIG_DEBUGGER */ |
138 | /* FALLTHROUGH */ | ||
131 | default: | 139 | default: |
132 | printk("SMP %d: smp_message_recv(): unknown msg %d\n", | 140 | printk("SMP %d: smp_message_recv(): unknown msg %d\n", |
133 | smp_processor_id(), msg); | 141 | smp_processor_id(), msg); |
@@ -147,6 +155,17 @@ void smp_send_debugger_break(int cpu) | |||
147 | } | 155 | } |
148 | #endif | 156 | #endif |
149 | 157 | ||
158 | #ifdef CONFIG_KEXEC | ||
159 | void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) | ||
160 | { | ||
161 | crash_ipi_function_ptr = crash_ipi_callback; | ||
162 | if (crash_ipi_callback) { | ||
163 | mb(); | ||
164 | smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK); | ||
165 | } | ||
166 | } | ||
167 | #endif | ||
168 | |||
150 | static void stop_this_cpu(void *dummy) | 169 | static void stop_this_cpu(void *dummy) |
151 | { | 170 | { |
152 | local_irq_disable(); | 171 | local_irq_disable(); |
@@ -452,10 +471,6 @@ int __devinit __cpu_up(unsigned int cpu) | |||
452 | if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)) | 471 | if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)) |
453 | return -EINVAL; | 472 | return -EINVAL; |
454 | 473 | ||
455 | #ifdef CONFIG_PPC64 | ||
456 | paca[cpu].default_decr = tb_ticks_per_jiffy; | ||
457 | #endif | ||
458 | |||
459 | /* Make sure callin-map entry is 0 (can be leftover a CPU | 474 | /* Make sure callin-map entry is 0 (can be leftover a CPU |
460 | * hotplug | 475 | * hotplug |
461 | */ | 476 | */ |
@@ -554,6 +569,8 @@ void __init smp_cpus_done(unsigned int max_cpus) | |||
554 | smp_ops->setup_cpu(boot_cpuid); | 569 | smp_ops->setup_cpu(boot_cpuid); |
555 | 570 | ||
556 | set_cpus_allowed(current, old_mask); | 571 | set_cpus_allowed(current, old_mask); |
572 | |||
573 | dump_numa_cpu_topology(); | ||
557 | } | 574 | } |
558 | 575 | ||
559 | #ifdef CONFIG_HOTPLUG_CPU | 576 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 91b93d917b64..ad895c99813b 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c | |||
@@ -43,9 +43,6 @@ | |||
43 | #include <asm/time.h> | 43 | #include <asm/time.h> |
44 | #include <asm/unistd.h> | 44 | #include <asm/unistd.h> |
45 | 45 | ||
46 | extern unsigned long wall_jiffies; | ||
47 | |||
48 | |||
49 | /* | 46 | /* |
50 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | 47 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. |
51 | * | 48 | * |
@@ -311,31 +308,6 @@ int sys_olduname(struct oldold_utsname __user *name) | |||
311 | return error? -EFAULT: 0; | 308 | return error? -EFAULT: 0; |
312 | } | 309 | } |
313 | 310 | ||
314 | #ifdef CONFIG_PPC64 | ||
315 | time_t sys64_time(time_t __user * tloc) | ||
316 | { | ||
317 | time_t secs; | ||
318 | time_t usecs; | ||
319 | |||
320 | long tb_delta = tb_ticks_since(tb_last_stamp); | ||
321 | tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; | ||
322 | |||
323 | secs = xtime.tv_sec; | ||
324 | usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec; | ||
325 | while (usecs >= USEC_PER_SEC) { | ||
326 | ++secs; | ||
327 | usecs -= USEC_PER_SEC; | ||
328 | } | ||
329 | |||
330 | if (tloc) { | ||
331 | if (put_user(secs,tloc)) | ||
332 | secs = -EFAULT; | ||
333 | } | ||
334 | |||
335 | return secs; | ||
336 | } | ||
337 | #endif | ||
338 | |||
339 | long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, | 311 | long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, |
340 | u32 len_high, u32 len_low) | 312 | u32 len_high, u32 len_low) |
341 | { | 313 | { |
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 65eaea91b499..65463a1076e8 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S | |||
@@ -54,7 +54,7 @@ SYSCALL(link) | |||
54 | SYSCALL(unlink) | 54 | SYSCALL(unlink) |
55 | COMPAT_SYS(execve) | 55 | COMPAT_SYS(execve) |
56 | SYSCALL(chdir) | 56 | SYSCALL(chdir) |
57 | SYSX(sys64_time,compat_sys_time,sys_time) | 57 | COMPAT_SYS(time) |
58 | SYSCALL(mknod) | 58 | SYSCALL(mknod) |
59 | SYSCALL(chmod) | 59 | SYSCALL(chmod) |
60 | SYSCALL(lchown) | 60 | SYSCALL(lchown) |
@@ -113,7 +113,7 @@ SYSCALL(sgetmask) | |||
113 | COMPAT_SYS(ssetmask) | 113 | COMPAT_SYS(ssetmask) |
114 | SYSCALL(setreuid) | 114 | SYSCALL(setreuid) |
115 | SYSCALL(setregid) | 115 | SYSCALL(setregid) |
116 | SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) | 116 | SYS32ONLY(sigsuspend) |
117 | COMPAT_SYS(sigpending) | 117 | COMPAT_SYS(sigpending) |
118 | COMPAT_SYS(sethostname) | 118 | COMPAT_SYS(sethostname) |
119 | COMPAT_SYS(setrlimit) | 119 | COMPAT_SYS(setrlimit) |
@@ -160,7 +160,7 @@ SYSCALL(swapoff) | |||
160 | COMPAT_SYS(sysinfo) | 160 | COMPAT_SYS(sysinfo) |
161 | COMPAT_SYS(ipc) | 161 | COMPAT_SYS(ipc) |
162 | SYSCALL(fsync) | 162 | SYSCALL(fsync) |
163 | SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) | 163 | SYS32ONLY(sigreturn) |
164 | PPC_SYS(clone) | 164 | PPC_SYS(clone) |
165 | COMPAT_SYS(setdomainname) | 165 | COMPAT_SYS(setdomainname) |
166 | PPC_SYS(newuname) | 166 | PPC_SYS(newuname) |
@@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl) | |||
213 | SYSCALL(setresgid) | 213 | SYSCALL(setresgid) |
214 | SYSCALL(getresgid) | 214 | SYSCALL(getresgid) |
215 | COMPAT_SYS(prctl) | 215 | COMPAT_SYS(prctl) |
216 | SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) | 216 | COMPAT_SYS(rt_sigreturn) |
217 | COMPAT_SYS(rt_sigaction) | 217 | COMPAT_SYS(rt_sigaction) |
218 | COMPAT_SYS(rt_sigprocmask) | 218 | COMPAT_SYS(rt_sigprocmask) |
219 | COMPAT_SYS(rt_sigpending) | 219 | COMPAT_SYS(rt_sigpending) |
220 | COMPAT_SYS(rt_sigtimedwait) | 220 | COMPAT_SYS(rt_sigtimedwait) |
221 | COMPAT_SYS(rt_sigqueueinfo) | 221 | COMPAT_SYS(rt_sigqueueinfo) |
222 | SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) | 222 | COMPAT_SYS(rt_sigsuspend) |
223 | COMPAT_SYS(pread64) | 223 | COMPAT_SYS(pread64) |
224 | COMPAT_SYS(pwrite64) | 224 | COMPAT_SYS(pwrite64) |
225 | SYSCALL(chown) | 225 | SYSCALL(chown) |
@@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime) | |||
290 | COMPAT_SYS(clock_gettime) | 290 | COMPAT_SYS(clock_gettime) |
291 | COMPAT_SYS(clock_getres) | 291 | COMPAT_SYS(clock_getres) |
292 | COMPAT_SYS(clock_nanosleep) | 292 | COMPAT_SYS(clock_nanosleep) |
293 | SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) | 293 | COMPAT_SYS(swapcontext) |
294 | COMPAT_SYS(tgkill) | 294 | COMPAT_SYS(tgkill) |
295 | COMPAT_SYS(utimes) | 295 | COMPAT_SYS(utimes) |
296 | COMPAT_SYS(statfs64) | 296 | COMPAT_SYS(statfs64) |
@@ -319,3 +319,5 @@ COMPAT_SYS(ioprio_get) | |||
319 | SYSCALL(inotify_init) | 319 | SYSCALL(inotify_init) |
320 | SYSCALL(inotify_add_watch) | 320 | SYSCALL(inotify_add_watch) |
321 | SYSCALL(inotify_rm_watch) | 321 | SYSCALL(inotify_rm_watch) |
322 | SYSCALL(spu_run) | ||
323 | SYSCALL(spu_create) | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index de8479769bb7..56f50e91bddb 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -699,10 +699,6 @@ void __init time_init(void) | |||
699 | div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res); | 699 | div128_by_32(1024*1024, 0, tb_ticks_per_sec, &res); |
700 | tb_to_xs = res.result_low; | 700 | tb_to_xs = res.result_low; |
701 | 701 | ||
702 | #ifdef CONFIG_PPC64 | ||
703 | get_paca()->default_decr = tb_ticks_per_jiffy; | ||
704 | #endif | ||
705 | |||
706 | /* | 702 | /* |
707 | * Compute scale factor for sched_clock. | 703 | * Compute scale factor for sched_clock. |
708 | * The calibrate_decr() function has set tb_ticks_per_sec, | 704 | * The calibrate_decr() function has set tb_ticks_per_sec, |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 1511454c4690..7509aa6474f2 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/prctl.h> | 31 | #include <linux/prctl.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/kprobes.h> | 33 | #include <linux/kprobes.h> |
34 | #include <linux/kexec.h> | ||
34 | 35 | ||
35 | #include <asm/kdebug.h> | 36 | #include <asm/kdebug.h> |
36 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
@@ -95,7 +96,7 @@ static DEFINE_SPINLOCK(die_lock); | |||
95 | 96 | ||
96 | int die(const char *str, struct pt_regs *regs, long err) | 97 | int die(const char *str, struct pt_regs *regs, long err) |
97 | { | 98 | { |
98 | static int die_counter; | 99 | static int die_counter, crash_dump_start = 0; |
99 | int nl = 0; | 100 | int nl = 0; |
100 | 101 | ||
101 | if (debugger(regs)) | 102 | if (debugger(regs)) |
@@ -156,7 +157,21 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
156 | print_modules(); | 157 | print_modules(); |
157 | show_regs(regs); | 158 | show_regs(regs); |
158 | bust_spinlocks(0); | 159 | bust_spinlocks(0); |
160 | |||
161 | if (!crash_dump_start && kexec_should_crash(current)) { | ||
162 | crash_dump_start = 1; | ||
163 | spin_unlock_irq(&die_lock); | ||
164 | crash_kexec(regs); | ||
165 | /* NOTREACHED */ | ||
166 | } | ||
159 | spin_unlock_irq(&die_lock); | 167 | spin_unlock_irq(&die_lock); |
168 | if (crash_dump_start) | ||
169 | /* | ||
170 | * Only for soft-reset: Other CPUs will be responded to an IPI | ||
171 | * sent by first kexec CPU. | ||
172 | */ | ||
173 | for(;;) | ||
174 | ; | ||
160 | 175 | ||
161 | if (in_interrupt()) | 176 | if (in_interrupt()) |
162 | panic("Fatal exception in interrupt"); | 177 | panic("Fatal exception in interrupt"); |
@@ -215,8 +230,10 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
215 | void system_reset_exception(struct pt_regs *regs) | 230 | void system_reset_exception(struct pt_regs *regs) |
216 | { | 231 | { |
217 | /* See if any machine dependent calls */ | 232 | /* See if any machine dependent calls */ |
218 | if (ppc_md.system_reset_exception) | 233 | if (ppc_md.system_reset_exception) { |
219 | ppc_md.system_reset_exception(regs); | 234 | if (ppc_md.system_reset_exception(regs)) |
235 | return; | ||
236 | } | ||
220 | 237 | ||
221 | die("System Reset", regs, SIGABRT); | 238 | die("System Reset", regs, SIGABRT); |
222 | 239 | ||
@@ -886,12 +903,10 @@ void altivec_unavailable_exception(struct pt_regs *regs) | |||
886 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); | 903 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); |
887 | } | 904 | } |
888 | 905 | ||
889 | #if defined(CONFIG_PPC64) || defined(CONFIG_E500) | ||
890 | void performance_monitor_exception(struct pt_regs *regs) | 906 | void performance_monitor_exception(struct pt_regs *regs) |
891 | { | 907 | { |
892 | perf_irq(regs); | 908 | perf_irq(regs); |
893 | } | 909 | } |
894 | #endif | ||
895 | 910 | ||
896 | #ifdef CONFIG_8xx | 911 | #ifdef CONFIG_8xx |
897 | void SoftwareEmulation(struct pt_regs *regs) | 912 | void SoftwareEmulation(struct pt_regs *regs) |
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 0d878e72fc44..558c1ceb2b93 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c | |||
@@ -16,8 +16,8 @@ | |||
16 | #include <linux/console.h> | 16 | #include <linux/console.h> |
17 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
18 | 18 | ||
19 | void (*udbg_putc)(unsigned char c); | 19 | void (*udbg_putc)(char c); |
20 | unsigned char (*udbg_getc)(void); | 20 | int (*udbg_getc)(void); |
21 | int (*udbg_getc_poll)(void); | 21 | int (*udbg_getc_poll)(void); |
22 | 22 | ||
23 | /* udbg library, used by xmon et al */ | 23 | /* udbg library, used by xmon et al */ |
@@ -57,8 +57,8 @@ int udbg_write(const char *s, int n) | |||
57 | 57 | ||
58 | int udbg_read(char *buf, int buflen) | 58 | int udbg_read(char *buf, int buflen) |
59 | { | 59 | { |
60 | char c, *p = buf; | 60 | char *p = buf; |
61 | int i; | 61 | int i, c; |
62 | 62 | ||
63 | if (!udbg_getc) | 63 | if (!udbg_getc) |
64 | return 0; | 64 | return 0; |
@@ -66,8 +66,11 @@ int udbg_read(char *buf, int buflen) | |||
66 | for (i = 0; i < buflen; ++i) { | 66 | for (i = 0; i < buflen; ++i) { |
67 | do { | 67 | do { |
68 | c = udbg_getc(); | 68 | c = udbg_getc(); |
69 | if (c == -1 && i == 0) | ||
70 | return -1; | ||
71 | |||
69 | } while (c == 0x11 || c == 0x13); | 72 | } while (c == 0x11 || c == 0x13); |
70 | if (c == 0) | 73 | if (c == 0 || c == -1) |
71 | break; | 74 | break; |
72 | *p++ = c; | 75 | *p++ = c; |
73 | } | 76 | } |
@@ -78,7 +81,7 @@ int udbg_read(char *buf, int buflen) | |||
78 | #define UDBG_BUFSIZE 256 | 81 | #define UDBG_BUFSIZE 256 |
79 | void udbg_printf(const char *fmt, ...) | 82 | void udbg_printf(const char *fmt, ...) |
80 | { | 83 | { |
81 | unsigned char buf[UDBG_BUFSIZE]; | 84 | char buf[UDBG_BUFSIZE]; |
82 | va_list args; | 85 | va_list args; |
83 | 86 | ||
84 | va_start(args, fmt); | 87 | va_start(args, fmt); |
@@ -87,6 +90,12 @@ void udbg_printf(const char *fmt, ...) | |||
87 | va_end(args); | 90 | va_end(args); |
88 | } | 91 | } |
89 | 92 | ||
93 | void __init udbg_progress(char *s, unsigned short hex) | ||
94 | { | ||
95 | udbg_puts(s); | ||
96 | udbg_puts("\n"); | ||
97 | } | ||
98 | |||
90 | /* | 99 | /* |
91 | * Early boot console based on udbg | 100 | * Early boot console based on udbg |
92 | */ | 101 | */ |
@@ -99,7 +108,7 @@ static void udbg_console_write(struct console *con, const char *s, | |||
99 | static struct console udbg_console = { | 108 | static struct console udbg_console = { |
100 | .name = "udbg", | 109 | .name = "udbg", |
101 | .write = udbg_console_write, | 110 | .write = udbg_console_write, |
102 | .flags = CON_PRINTBUFFER, | 111 | .flags = CON_PRINTBUFFER | CON_ENABLED, |
103 | .index = -1, | 112 | .index = -1, |
104 | }; | 113 | }; |
105 | 114 | ||
@@ -107,15 +116,19 @@ static int early_console_initialized; | |||
107 | 116 | ||
108 | void __init disable_early_printk(void) | 117 | void __init disable_early_printk(void) |
109 | { | 118 | { |
119 | #if 1 | ||
110 | if (!early_console_initialized) | 120 | if (!early_console_initialized) |
111 | return; | 121 | return; |
112 | unregister_console(&udbg_console); | 122 | unregister_console(&udbg_console); |
113 | early_console_initialized = 0; | 123 | early_console_initialized = 0; |
124 | #endif | ||
114 | } | 125 | } |
115 | 126 | ||
116 | /* called by setup_system */ | 127 | /* called by setup_system */ |
117 | void register_early_udbg_console(void) | 128 | void register_early_udbg_console(void) |
118 | { | 129 | { |
130 | if (early_console_initialized) | ||
131 | return; | ||
119 | early_console_initialized = 1; | 132 | early_console_initialized = 1; |
120 | register_console(&udbg_console); | 133 | register_console(&udbg_console); |
121 | } | 134 | } |
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 9313574ab935..7541bf44d2da 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c | |||
@@ -43,9 +43,11 @@ struct NS16550 { | |||
43 | #define LSR_TEMT 0x40 /* Xmitter empty */ | 43 | #define LSR_TEMT 0x40 /* Xmitter empty */ |
44 | #define LSR_ERR 0x80 /* Error */ | 44 | #define LSR_ERR 0x80 /* Error */ |
45 | 45 | ||
46 | #define LCR_DLAB 0x80 | ||
47 | |||
46 | static volatile struct NS16550 __iomem *udbg_comport; | 48 | static volatile struct NS16550 __iomem *udbg_comport; |
47 | 49 | ||
48 | static void udbg_550_putc(unsigned char c) | 50 | static void udbg_550_putc(char c) |
49 | { | 51 | { |
50 | if (udbg_comport) { | 52 | if (udbg_comport) { |
51 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) | 53 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) |
@@ -67,39 +69,80 @@ static int udbg_550_getc_poll(void) | |||
67 | return -1; | 69 | return -1; |
68 | } | 70 | } |
69 | 71 | ||
70 | static unsigned char udbg_550_getc(void) | 72 | static int udbg_550_getc(void) |
71 | { | 73 | { |
72 | if (udbg_comport) { | 74 | if (udbg_comport) { |
73 | while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) | 75 | while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0) |
74 | /* wait for char */; | 76 | /* wait for char */; |
75 | return in_8(&udbg_comport->rbr); | 77 | return in_8(&udbg_comport->rbr); |
76 | } | 78 | } |
77 | return 0; | 79 | return -1; |
78 | } | 80 | } |
79 | 81 | ||
80 | void udbg_init_uart(void __iomem *comport, unsigned int speed) | 82 | void udbg_init_uart(void __iomem *comport, unsigned int speed, |
83 | unsigned int clock) | ||
81 | { | 84 | { |
82 | u16 dll = speed ? (115200 / speed) : 12; | 85 | unsigned int dll, base_bauds = clock / 16; |
86 | |||
87 | if (speed == 0) | ||
88 | speed = 9600; | ||
89 | dll = base_bauds / speed; | ||
83 | 90 | ||
84 | if (comport) { | 91 | if (comport) { |
85 | udbg_comport = (struct NS16550 __iomem *)comport; | 92 | udbg_comport = (struct NS16550 __iomem *)comport; |
86 | out_8(&udbg_comport->lcr, 0x00); | 93 | out_8(&udbg_comport->lcr, 0x00); |
87 | out_8(&udbg_comport->ier, 0xff); | 94 | out_8(&udbg_comport->ier, 0xff); |
88 | out_8(&udbg_comport->ier, 0x00); | 95 | out_8(&udbg_comport->ier, 0x00); |
89 | out_8(&udbg_comport->lcr, 0x80); /* Access baud rate */ | 96 | out_8(&udbg_comport->lcr, LCR_DLAB); |
90 | out_8(&udbg_comport->dll, dll & 0xff); /* 1 = 115200, 2 = 57600, | 97 | out_8(&udbg_comport->dll, dll & 0xff); |
91 | 3 = 38400, 12 = 9600 baud */ | 98 | out_8(&udbg_comport->dlm, dll >> 8); |
92 | out_8(&udbg_comport->dlm, dll >> 8); /* dll >> 8 which should be zero | 99 | /* 8 data, 1 stop, no parity */ |
93 | for fast rates; */ | 100 | out_8(&udbg_comport->lcr, 0x03); |
94 | out_8(&udbg_comport->lcr, 0x03); /* 8 data, 1 stop, no parity */ | 101 | /* RTS/DTR */ |
95 | out_8(&udbg_comport->mcr, 0x03); /* RTS/DTR */ | 102 | out_8(&udbg_comport->mcr, 0x03); |
96 | out_8(&udbg_comport->fcr ,0x07); /* Clear & enable FIFOs */ | 103 | /* Clear & enable FIFOs */ |
104 | out_8(&udbg_comport->fcr ,0x07); | ||
97 | udbg_putc = udbg_550_putc; | 105 | udbg_putc = udbg_550_putc; |
98 | udbg_getc = udbg_550_getc; | 106 | udbg_getc = udbg_550_getc; |
99 | udbg_getc_poll = udbg_550_getc_poll; | 107 | udbg_getc_poll = udbg_550_getc_poll; |
100 | } | 108 | } |
101 | } | 109 | } |
102 | 110 | ||
111 | unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock) | ||
112 | { | ||
113 | unsigned int dll, dlm, divisor, prescaler, speed; | ||
114 | u8 old_lcr; | ||
115 | volatile struct NS16550 __iomem *port = comport; | ||
116 | |||
117 | old_lcr = in_8(&port->lcr); | ||
118 | |||
119 | /* select divisor latch registers. */ | ||
120 | out_8(&port->lcr, LCR_DLAB); | ||
121 | |||
122 | /* now, read the divisor */ | ||
123 | dll = in_8(&port->dll); | ||
124 | dlm = in_8(&port->dlm); | ||
125 | divisor = dlm << 8 | dll; | ||
126 | |||
127 | /* check prescaling */ | ||
128 | if (in_8(&port->mcr) & 0x80) | ||
129 | prescaler = 4; | ||
130 | else | ||
131 | prescaler = 1; | ||
132 | |||
133 | /* restore the LCR */ | ||
134 | out_8(&port->lcr, old_lcr); | ||
135 | |||
136 | /* calculate speed */ | ||
137 | speed = (clock / prescaler) / (divisor * 16); | ||
138 | |||
139 | /* sanity check */ | ||
140 | if (speed < 0 || speed > (clock / 16)) | ||
141 | speed = 9600; | ||
142 | |||
143 | return speed; | ||
144 | } | ||
145 | |||
103 | #ifdef CONFIG_PPC_MAPLE | 146 | #ifdef CONFIG_PPC_MAPLE |
104 | void udbg_maple_real_putc(unsigned char c) | 147 | void udbg_maple_real_putc(unsigned char c) |
105 | { | 148 | { |
diff --git a/arch/powerpc/kernel/udbg_scc.c b/arch/powerpc/kernel/udbg_scc.c deleted file mode 100644 index 820c53551507..000000000000 --- a/arch/powerpc/kernel/udbg_scc.c +++ /dev/null | |||
@@ -1,135 +0,0 @@ | |||
1 | /* | ||
2 | * udbg for for zilog scc ports as found on Apple PowerMacs | ||
3 | * | ||
4 | * Copyright (C) 2001-2005 PPC 64 Team, 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 | #include <linux/config.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <asm/udbg.h> | ||
14 | #include <asm/processor.h> | ||
15 | #include <asm/io.h> | ||
16 | #include <asm/prom.h> | ||
17 | #include <asm/pmac_feature.h> | ||
18 | |||
19 | extern u8 real_readb(volatile u8 __iomem *addr); | ||
20 | extern void real_writeb(u8 data, volatile u8 __iomem *addr); | ||
21 | |||
22 | #define SCC_TXRDY 4 | ||
23 | #define SCC_RXRDY 1 | ||
24 | |||
25 | static volatile u8 __iomem *sccc; | ||
26 | static volatile u8 __iomem *sccd; | ||
27 | |||
28 | static void udbg_scc_putc(unsigned char c) | ||
29 | { | ||
30 | if (sccc) { | ||
31 | while ((in_8(sccc) & SCC_TXRDY) == 0) | ||
32 | ; | ||
33 | out_8(sccd, c); | ||
34 | if (c == '\n') | ||
35 | udbg_scc_putc('\r'); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | static int udbg_scc_getc_poll(void) | ||
40 | { | ||
41 | if (sccc) { | ||
42 | if ((in_8(sccc) & SCC_RXRDY) != 0) | ||
43 | return in_8(sccd); | ||
44 | else | ||
45 | return -1; | ||
46 | } | ||
47 | return -1; | ||
48 | } | ||
49 | |||
50 | static unsigned char udbg_scc_getc(void) | ||
51 | { | ||
52 | if (sccc) { | ||
53 | while ((in_8(sccc) & SCC_RXRDY) == 0) | ||
54 | ; | ||
55 | return in_8(sccd); | ||
56 | } | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static unsigned char scc_inittab[] = { | ||
61 | 13, 0, /* set baud rate divisor */ | ||
62 | 12, 0, | ||
63 | 14, 1, /* baud rate gen enable, src=rtxc */ | ||
64 | 11, 0x50, /* clocks = br gen */ | ||
65 | 5, 0xea, /* tx 8 bits, assert DTR & RTS */ | ||
66 | 4, 0x46, /* x16 clock, 1 stop */ | ||
67 | 3, 0xc1, /* rx enable, 8 bits */ | ||
68 | }; | ||
69 | |||
70 | void udbg_init_scc(struct device_node *np) | ||
71 | { | ||
72 | u32 *reg; | ||
73 | unsigned long addr; | ||
74 | int i, x; | ||
75 | |||
76 | if (np == NULL) | ||
77 | np = of_find_node_by_name(NULL, "escc"); | ||
78 | if (np == NULL || np->parent == NULL) | ||
79 | return; | ||
80 | |||
81 | udbg_printf("found SCC...\n"); | ||
82 | /* Get address within mac-io ASIC */ | ||
83 | reg = (u32 *)get_property(np, "reg", NULL); | ||
84 | if (reg == NULL) | ||
85 | return; | ||
86 | addr = reg[0]; | ||
87 | udbg_printf("local addr: %lx\n", addr); | ||
88 | /* Get address of mac-io PCI itself */ | ||
89 | reg = (u32 *)get_property(np->parent, "assigned-addresses", NULL); | ||
90 | if (reg == NULL) | ||
91 | return; | ||
92 | addr += reg[2]; | ||
93 | udbg_printf("final addr: %lx\n", addr); | ||
94 | |||
95 | /* Setup for 57600 8N1 */ | ||
96 | addr += 0x20; | ||
97 | sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; | ||
98 | sccc += addr & ~PAGE_MASK; | ||
99 | sccd = sccc + 0x10; | ||
100 | |||
101 | udbg_printf("ioremap result sccc: %p\n", sccc); | ||
102 | mb(); | ||
103 | |||
104 | for (i = 20000; i != 0; --i) | ||
105 | x = in_8(sccc); | ||
106 | out_8(sccc, 0x09); /* reset A or B side */ | ||
107 | out_8(sccc, 0xc0); | ||
108 | for (i = 0; i < sizeof(scc_inittab); ++i) | ||
109 | out_8(sccc, scc_inittab[i]); | ||
110 | |||
111 | udbg_putc = udbg_scc_putc; | ||
112 | udbg_getc = udbg_scc_getc; | ||
113 | udbg_getc_poll = udbg_scc_getc_poll; | ||
114 | |||
115 | udbg_puts("Hello World !\n"); | ||
116 | } | ||
117 | |||
118 | static void udbg_real_scc_putc(unsigned char c) | ||
119 | { | ||
120 | while ((real_readb(sccc) & SCC_TXRDY) == 0) | ||
121 | ; | ||
122 | real_writeb(c, sccd); | ||
123 | if (c == '\n') | ||
124 | udbg_real_scc_putc('\r'); | ||
125 | } | ||
126 | |||
127 | void udbg_init_pmac_realmode(void) | ||
128 | { | ||
129 | sccc = (volatile u8 __iomem *)0x80013020ul; | ||
130 | sccd = (volatile u8 __iomem *)0x80013030ul; | ||
131 | |||
132 | udbg_putc = udbg_real_scc_putc; | ||
133 | udbg_getc = NULL; | ||
134 | udbg_getc_poll = NULL; | ||
135 | } | ||