diff options
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r-- | arch/ppc/kernel/misc.S | 74 | ||||
-rw-r--r-- | arch/ppc/kernel/pci.c | 41 | ||||
-rw-r--r-- | arch/ppc/kernel/setup.c | 10 | ||||
-rw-r--r-- | arch/ppc/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/ppc/kernel/traps.c | 84 | ||||
-rw-r--r-- | arch/ppc/kernel/vmlinux.lds.S | 9 |
6 files changed, 61 insertions, 161 deletions
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 5f6684012ded..d319f9ba2379 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S | |||
@@ -110,80 +110,6 @@ _GLOBAL(reloc_got2) | |||
110 | blr | 110 | blr |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * identify_cpu, | ||
114 | * called with r3 = data offset and r4 = CPU number | ||
115 | * doesn't change r3 | ||
116 | */ | ||
117 | _GLOBAL(identify_cpu) | ||
118 | addis r8,r3,cpu_specs@ha | ||
119 | addi r8,r8,cpu_specs@l | ||
120 | mfpvr r7 | ||
121 | 1: | ||
122 | lwz r5,CPU_SPEC_PVR_MASK(r8) | ||
123 | and r5,r5,r7 | ||
124 | lwz r6,CPU_SPEC_PVR_VALUE(r8) | ||
125 | cmplw 0,r6,r5 | ||
126 | beq 1f | ||
127 | addi r8,r8,CPU_SPEC_ENTRY_SIZE | ||
128 | b 1b | ||
129 | 1: | ||
130 | addis r6,r3,cur_cpu_spec@ha | ||
131 | addi r6,r6,cur_cpu_spec@l | ||
132 | sub r8,r8,r3 | ||
133 | stw r8,0(r6) | ||
134 | blr | ||
135 | |||
136 | /* | ||
137 | * do_cpu_ftr_fixups - goes through the list of CPU feature fixups | ||
138 | * and writes nop's over sections of code that don't apply for this cpu. | ||
139 | * r3 = data offset (not changed) | ||
140 | */ | ||
141 | _GLOBAL(do_cpu_ftr_fixups) | ||
142 | /* Get CPU 0 features */ | ||
143 | addis r6,r3,cur_cpu_spec@ha | ||
144 | addi r6,r6,cur_cpu_spec@l | ||
145 | lwz r4,0(r6) | ||
146 | add r4,r4,r3 | ||
147 | lwz r4,CPU_SPEC_FEATURES(r4) | ||
148 | |||
149 | /* Get the fixup table */ | ||
150 | addis r6,r3,__start___ftr_fixup@ha | ||
151 | addi r6,r6,__start___ftr_fixup@l | ||
152 | addis r7,r3,__stop___ftr_fixup@ha | ||
153 | addi r7,r7,__stop___ftr_fixup@l | ||
154 | |||
155 | /* Do the fixup */ | ||
156 | 1: cmplw 0,r6,r7 | ||
157 | bgelr | ||
158 | addi r6,r6,16 | ||
159 | lwz r8,-16(r6) /* mask */ | ||
160 | and r8,r8,r4 | ||
161 | lwz r9,-12(r6) /* value */ | ||
162 | cmplw 0,r8,r9 | ||
163 | beq 1b | ||
164 | lwz r8,-8(r6) /* section begin */ | ||
165 | lwz r9,-4(r6) /* section end */ | ||
166 | subf. r9,r8,r9 | ||
167 | beq 1b | ||
168 | /* write nops over the section of code */ | ||
169 | /* todo: if large section, add a branch at the start of it */ | ||
170 | srwi r9,r9,2 | ||
171 | mtctr r9 | ||
172 | add r8,r8,r3 | ||
173 | lis r0,0x60000000@h /* nop */ | ||
174 | 3: stw r0,0(r8) | ||
175 | andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l | ||
176 | beq 2f | ||
177 | dcbst 0,r8 /* suboptimal, but simpler */ | ||
178 | sync | ||
179 | icbi 0,r8 | ||
180 | 2: addi r8,r8,4 | ||
181 | bdnz 3b | ||
182 | sync /* additional sync needed on g4 */ | ||
183 | isync | ||
184 | b 1b | ||
185 | |||
186 | /* | ||
187 | * call_setup_cpu - call the setup_cpu function for this cpu | 113 | * call_setup_cpu - call the setup_cpu function for this cpu |
188 | * r3 = data offset, r24 = cpu number | 114 | * r3 = data offset, r24 = cpu number |
189 | * | 115 | * |
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 63808e01cb0b..5e723c4c2571 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c | |||
@@ -879,7 +879,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) | |||
879 | 879 | ||
880 | 880 | ||
881 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | 881 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, |
882 | unsigned long *offset, | 882 | resource_size_t *offset, |
883 | enum pci_mmap_state mmap_state) | 883 | enum pci_mmap_state mmap_state) |
884 | { | 884 | { |
885 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | 885 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); |
@@ -891,7 +891,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
891 | 891 | ||
892 | /* If memory, add on the PCI bridge address offset */ | 892 | /* If memory, add on the PCI bridge address offset */ |
893 | if (mmap_state == pci_mmap_mem) { | 893 | if (mmap_state == pci_mmap_mem) { |
894 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
894 | *offset += hose->pci_mem_offset; | 895 | *offset += hose->pci_mem_offset; |
896 | #endif | ||
895 | res_bit = IORESOURCE_MEM; | 897 | res_bit = IORESOURCE_MEM; |
896 | } else { | 898 | } else { |
897 | io_offset = hose->io_base_virt - ___IO_BASE; | 899 | io_offset = hose->io_base_virt - ___IO_BASE; |
@@ -1030,7 +1032,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | |||
1030 | enum pci_mmap_state mmap_state, | 1032 | enum pci_mmap_state mmap_state, |
1031 | int write_combine) | 1033 | int write_combine) |
1032 | { | 1034 | { |
1033 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 1035 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; |
1034 | struct resource *rp; | 1036 | struct resource *rp; |
1035 | int ret; | 1037 | int ret; |
1036 | 1038 | ||
@@ -1132,21 +1134,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, | |||
1132 | resource_size_t *start, resource_size_t *end) | 1134 | resource_size_t *start, resource_size_t *end) |
1133 | { | 1135 | { |
1134 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | 1136 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); |
1135 | unsigned long offset = 0; | 1137 | resource_size_t offset = 0; |
1136 | 1138 | ||
1137 | if (hose == NULL) | 1139 | if (hose == NULL) |
1138 | return; | 1140 | return; |
1139 | 1141 | ||
1140 | if (rsrc->flags & IORESOURCE_IO) | 1142 | if (rsrc->flags & IORESOURCE_IO) |
1141 | offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; | 1143 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; |
1144 | |||
1145 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
1146 | * a BAR value because X is lame and expects to be able to use that | ||
1147 | * to pass to /dev/mem ! | ||
1148 | * | ||
1149 | * That means that we'll have potentially 64 bits values where some | ||
1150 | * userland apps only expect 32 (like X itself since it thinks only | ||
1151 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
1152 | * 32 bits CHRPs :-( | ||
1153 | * | ||
1154 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
1155 | * has been fixed (and the fix spread enough), we can re-enable the | ||
1156 | * 2 lines below and pass down a BAR value to userland. In that case | ||
1157 | * we'll also have to re-enable the matching code in | ||
1158 | * __pci_mmap_make_offset(). | ||
1159 | * | ||
1160 | * BenH. | ||
1161 | */ | ||
1162 | #if 0 | ||
1163 | else if (rsrc->flags & IORESOURCE_MEM) | ||
1164 | offset = hose->pci_mem_offset; | ||
1165 | #endif | ||
1142 | 1166 | ||
1143 | *start = rsrc->start + offset; | 1167 | *start = rsrc->start - offset; |
1144 | *end = rsrc->end + offset; | 1168 | *end = rsrc->end - offset; |
1145 | } | 1169 | } |
1146 | 1170 | ||
1147 | void __init | 1171 | void __init pci_init_resource(struct resource *res, resource_size_t start, |
1148 | pci_init_resource(struct resource *res, unsigned long start, unsigned long end, | 1172 | resource_size_t end, int flags, char *name) |
1149 | int flags, char *name) | ||
1150 | { | 1173 | { |
1151 | res->start = start; | 1174 | res->start = start; |
1152 | res->end = end; | 1175 | res->end = end; |
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 75fe13815be2..3c506af19880 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <asm/nvram.h> | 38 | #include <asm/nvram.h> |
39 | #include <asm/xmon.h> | 39 | #include <asm/xmon.h> |
40 | #include <asm/ocp.h> | 40 | #include <asm/ocp.h> |
41 | #include <asm/prom.h> | ||
41 | 42 | ||
42 | #define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \ | 43 | #define USES_PPC_SYS (defined(CONFIG_85xx) || defined(CONFIG_83xx) || \ |
43 | defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \ | 44 | defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \ |
@@ -53,8 +54,6 @@ | |||
53 | 54 | ||
54 | extern void platform_init(unsigned long r3, unsigned long r4, | 55 | extern void platform_init(unsigned long r3, unsigned long r4, |
55 | unsigned long r5, unsigned long r6, unsigned long r7); | 56 | unsigned long r5, unsigned long r6, unsigned long r7); |
56 | extern void identify_cpu(unsigned long offset, unsigned long cpu); | ||
57 | extern void do_cpu_ftr_fixups(unsigned long offset); | ||
58 | extern void reloc_got2(unsigned long offset); | 57 | extern void reloc_got2(unsigned long offset); |
59 | 58 | ||
60 | extern void ppc6xx_idle(void); | 59 | extern void ppc6xx_idle(void); |
@@ -301,6 +300,7 @@ early_init(int r3, int r4, int r5) | |||
301 | { | 300 | { |
302 | unsigned long phys; | 301 | unsigned long phys; |
303 | unsigned long offset = reloc_offset(); | 302 | unsigned long offset = reloc_offset(); |
303 | struct cpu_spec *spec; | ||
304 | 304 | ||
305 | /* Default */ | 305 | /* Default */ |
306 | phys = offset + KERNELBASE; | 306 | phys = offset + KERNELBASE; |
@@ -313,8 +313,10 @@ early_init(int r3, int r4, int r5) | |||
313 | * Identify the CPU type and fix up code sections | 313 | * Identify the CPU type and fix up code sections |
314 | * that depend on which cpu we have. | 314 | * that depend on which cpu we have. |
315 | */ | 315 | */ |
316 | identify_cpu(offset, 0); | 316 | spec = identify_cpu(offset, mfspr(SPRN_PVR)); |
317 | do_cpu_ftr_fixups(offset); | 317 | do_feature_fixups(spec->cpu_features, |
318 | PTRRELOC(&__start___ftr_fixup), | ||
319 | PTRRELOC(&__stop___ftr_fixup)); | ||
318 | 320 | ||
319 | return phys; | 321 | return phys; |
320 | } | 322 | } |
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index d4b2cf74da6a..18ee851e33e3 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <asm/cache.h> | 62 | #include <asm/cache.h> |
63 | #include <asm/8xx_immap.h> | 63 | #include <asm/8xx_immap.h> |
64 | #include <asm/machdep.h> | 64 | #include <asm/machdep.h> |
65 | #include <asm/irq_regs.h> | ||
65 | 66 | ||
66 | #include <asm/time.h> | 67 | #include <asm/time.h> |
67 | 68 | ||
@@ -129,6 +130,7 @@ void wakeup_decrementer(void) | |||
129 | */ | 130 | */ |
130 | void timer_interrupt(struct pt_regs * regs) | 131 | void timer_interrupt(struct pt_regs * regs) |
131 | { | 132 | { |
133 | struct pt_regs *old_regs; | ||
132 | int next_dec; | 134 | int next_dec; |
133 | unsigned long cpu = smp_processor_id(); | 135 | unsigned long cpu = smp_processor_id(); |
134 | unsigned jiffy_stamp = last_jiffy_stamp(cpu); | 136 | unsigned jiffy_stamp = last_jiffy_stamp(cpu); |
@@ -137,6 +139,7 @@ void timer_interrupt(struct pt_regs * regs) | |||
137 | if (atomic_read(&ppc_n_lost_interrupts) != 0) | 139 | if (atomic_read(&ppc_n_lost_interrupts) != 0) |
138 | do_IRQ(regs); | 140 | do_IRQ(regs); |
139 | 141 | ||
142 | old_regs = set_irq_regs(regs); | ||
140 | irq_enter(); | 143 | irq_enter(); |
141 | 144 | ||
142 | while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { | 145 | while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { |
@@ -188,6 +191,7 @@ void timer_interrupt(struct pt_regs * regs) | |||
188 | ppc_md.heartbeat(); | 191 | ppc_md.heartbeat(); |
189 | 192 | ||
190 | irq_exit(); | 193 | irq_exit(); |
194 | set_irq_regs(old_regs); | ||
191 | } | 195 | } |
192 | 196 | ||
193 | /* | 197 | /* |
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index aafc8e8893d1..810f7aa72e92 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/prctl.h> | 30 | #include <linux/prctl.h> |
31 | #include <linux/bug.h> | ||
31 | 32 | ||
32 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
@@ -316,7 +317,7 @@ void machine_check_exception(struct pt_regs *regs) | |||
316 | if (reason & MCSR_BUS_RBERR) | 317 | if (reason & MCSR_BUS_RBERR) |
317 | printk("Bus - Read Data Bus Error\n"); | 318 | printk("Bus - Read Data Bus Error\n"); |
318 | if (reason & MCSR_BUS_WBERR) | 319 | if (reason & MCSR_BUS_WBERR) |
319 | printk("Bus - Read Data Bus Error\n"); | 320 | printk("Bus - Write Data Bus Error\n"); |
320 | if (reason & MCSR_BUS_IPERR) | 321 | if (reason & MCSR_BUS_IPERR) |
321 | printk("Bus - Instruction Parity Error\n"); | 322 | printk("Bus - Instruction Parity Error\n"); |
322 | if (reason & MCSR_BUS_RPERR) | 323 | if (reason & MCSR_BUS_RPERR) |
@@ -559,64 +560,9 @@ static void emulate_single_step(struct pt_regs *regs) | |||
559 | } | 560 | } |
560 | } | 561 | } |
561 | 562 | ||
562 | /* | 563 | int is_valid_bugaddr(unsigned long addr) |
563 | * Look through the list of trap instructions that are used for BUG(), | ||
564 | * BUG_ON() and WARN_ON() and see if we hit one. At this point we know | ||
565 | * that the exception was caused by a trap instruction of some kind. | ||
566 | * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 | ||
567 | * otherwise. | ||
568 | */ | ||
569 | extern struct bug_entry __start___bug_table[], __stop___bug_table[]; | ||
570 | |||
571 | #ifndef CONFIG_MODULES | ||
572 | #define module_find_bug(x) NULL | ||
573 | #endif | ||
574 | |||
575 | struct bug_entry *find_bug(unsigned long bugaddr) | ||
576 | { | 564 | { |
577 | struct bug_entry *bug; | 565 | return addr >= PAGE_OFFSET; |
578 | |||
579 | for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) | ||
580 | if (bugaddr == bug->bug_addr) | ||
581 | return bug; | ||
582 | return module_find_bug(bugaddr); | ||
583 | } | ||
584 | |||
585 | int check_bug_trap(struct pt_regs *regs) | ||
586 | { | ||
587 | struct bug_entry *bug; | ||
588 | unsigned long addr; | ||
589 | |||
590 | if (regs->msr & MSR_PR) | ||
591 | return 0; /* not in kernel */ | ||
592 | addr = regs->nip; /* address of trap instruction */ | ||
593 | if (addr < PAGE_OFFSET) | ||
594 | return 0; | ||
595 | bug = find_bug(regs->nip); | ||
596 | if (bug == NULL) | ||
597 | return 0; | ||
598 | if (bug->line & BUG_WARNING_TRAP) { | ||
599 | /* this is a WARN_ON rather than BUG/BUG_ON */ | ||
600 | #ifdef CONFIG_XMON | ||
601 | xmon_printf(KERN_ERR "Badness in %s at %s:%ld\n", | ||
602 | bug->function, bug->file, | ||
603 | bug->line & ~BUG_WARNING_TRAP); | ||
604 | #endif /* CONFIG_XMON */ | ||
605 | printk(KERN_ERR "Badness in %s at %s:%ld\n", | ||
606 | bug->function, bug->file, | ||
607 | bug->line & ~BUG_WARNING_TRAP); | ||
608 | dump_stack(); | ||
609 | return 1; | ||
610 | } | ||
611 | #ifdef CONFIG_XMON | ||
612 | xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", | ||
613 | bug->function, bug->file, bug->line); | ||
614 | xmon(regs); | ||
615 | #endif /* CONFIG_XMON */ | ||
616 | printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", | ||
617 | bug->function, bug->file, bug->line); | ||
618 | |||
619 | return 0; | ||
620 | } | 566 | } |
621 | 567 | ||
622 | void program_check_exception(struct pt_regs *regs) | 568 | void program_check_exception(struct pt_regs *regs) |
@@ -671,7 +617,9 @@ void program_check_exception(struct pt_regs *regs) | |||
671 | /* trap exception */ | 617 | /* trap exception */ |
672 | if (debugger_bpt(regs)) | 618 | if (debugger_bpt(regs)) |
673 | return; | 619 | return; |
674 | if (check_bug_trap(regs)) { | 620 | |
621 | if (!(regs->msr & MSR_PR) && /* not user-mode */ | ||
622 | report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) { | ||
675 | regs->nip += 4; | 623 | regs->nip += 4; |
676 | return; | 624 | return; |
677 | } | 625 | } |
@@ -708,7 +656,7 @@ void single_step_exception(struct pt_regs *regs) | |||
708 | 656 | ||
709 | void alignment_exception(struct pt_regs *regs) | 657 | void alignment_exception(struct pt_regs *regs) |
710 | { | 658 | { |
711 | int fixed; | 659 | int sig, code, fixed = 0; |
712 | 660 | ||
713 | fixed = fix_alignment(regs); | 661 | fixed = fix_alignment(regs); |
714 | if (fixed == 1) { | 662 | if (fixed == 1) { |
@@ -717,14 +665,16 @@ void alignment_exception(struct pt_regs *regs) | |||
717 | return; | 665 | return; |
718 | } | 666 | } |
719 | if (fixed == -EFAULT) { | 667 | if (fixed == -EFAULT) { |
720 | /* fixed == -EFAULT means the operand address was bad */ | 668 | sig = SIGSEGV; |
721 | if (user_mode(regs)) | 669 | code = SEGV_ACCERR; |
722 | _exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar); | 670 | } else { |
723 | else | 671 | sig = SIGBUS; |
724 | bad_page_fault(regs, regs->dar, SIGSEGV); | 672 | code = BUS_ADRALN; |
725 | return; | ||
726 | } | 673 | } |
727 | _exception(SIGBUS, regs, BUS_ADRALN, regs->dar); | 674 | if (user_mode(regs)) |
675 | _exception(sig, regs, code, regs->dar); | ||
676 | else | ||
677 | bad_page_fault(regs, regs->dar, sig); | ||
728 | } | 678 | } |
729 | 679 | ||
730 | void StackOverflow(struct pt_regs *regs) | 680 | void StackOverflow(struct pt_regs *regs) |
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index 095fd3323323..61921268a0d0 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S | |||
@@ -31,6 +31,7 @@ SECTIONS | |||
31 | .plt : { *(.plt) } | 31 | .plt : { *(.plt) } |
32 | .text : | 32 | .text : |
33 | { | 33 | { |
34 | _text = .; | ||
34 | *(.text) | 35 | *(.text) |
35 | SCHED_TEXT | 36 | SCHED_TEXT |
36 | LOCK_TEXT | 37 | LOCK_TEXT |
@@ -115,13 +116,7 @@ SECTIONS | |||
115 | __setup_end = .; | 116 | __setup_end = .; |
116 | __initcall_start = .; | 117 | __initcall_start = .; |
117 | .initcall.init : { | 118 | .initcall.init : { |
118 | *(.initcall1.init) | 119 | INITCALLS |
119 | *(.initcall2.init) | ||
120 | *(.initcall3.init) | ||
121 | *(.initcall4.init) | ||
122 | *(.initcall5.init) | ||
123 | *(.initcall6.init) | ||
124 | *(.initcall7.init) | ||
125 | } | 120 | } |
126 | __initcall_end = .; | 121 | __initcall_end = .; |
127 | 122 | ||