diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 78 |
1 files changed, 47 insertions, 31 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 56464cb8edf3..d3cbcd6bd985 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c | |||
@@ -1,30 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * File: arch/blackfin/kernel/traps.c | 2 | * Copyright 2004-2009 Analog Devices Inc. |
3 | * Based on: | ||
4 | * Author: Hamish Macdonald | ||
5 | * | 3 | * |
6 | * Created: | 4 | * Licensed under the GPL-2 or later |
7 | * Description: uses S/W interrupt 15 for the system calls | ||
8 | * | ||
9 | * Modified: | ||
10 | * Copyright 2004-2006 Analog Devices Inc. | ||
11 | * | ||
12 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, see the file COPYING, or write | ||
26 | * to the Free Software Foundation, Inc., | ||
27 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
28 | */ | 5 | */ |
29 | 6 | ||
30 | #include <linux/bug.h> | 7 | #include <linux/bug.h> |
@@ -142,6 +119,15 @@ static void decode_address(char *buf, unsigned long address) | |||
142 | return; | 119 | return; |
143 | } | 120 | } |
144 | 121 | ||
122 | /* | ||
123 | * Don't walk any of the vmas if we are oopsing, it has been known | ||
124 | * to cause problems - corrupt vmas (kernel crashes) cause double faults | ||
125 | */ | ||
126 | if (oops_in_progress) { | ||
127 | strcat(buf, "/* kernel dynamic memory (maybe user-space) */"); | ||
128 | return; | ||
129 | } | ||
130 | |||
145 | /* looks like we're off in user-land, so let's walk all the | 131 | /* looks like we're off in user-land, so let's walk all the |
146 | * mappings of all our processes and see if we can't be a whee | 132 | * mappings of all our processes and see if we can't be a whee |
147 | * bit more specific | 133 | * bit more specific |
@@ -538,6 +524,36 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
538 | break; | 524 | break; |
539 | /* External Memory Addressing Error */ | 525 | /* External Memory Addressing Error */ |
540 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): | 526 | case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): |
527 | if (ANOMALY_05000310) { | ||
528 | static unsigned long anomaly_rets; | ||
529 | |||
530 | if ((fp->pc >= (L1_CODE_START + L1_CODE_LENGTH - 512)) && | ||
531 | (fp->pc < (L1_CODE_START + L1_CODE_LENGTH))) { | ||
532 | /* | ||
533 | * A false hardware error will happen while fetching at | ||
534 | * the L1 instruction SRAM boundary. Ignore it. | ||
535 | */ | ||
536 | anomaly_rets = fp->rets; | ||
537 | goto traps_done; | ||
538 | } else if (fp->rets == anomaly_rets) { | ||
539 | /* | ||
540 | * While boundary code returns to a function, at the ret | ||
541 | * point, a new false hardware error might occur too based | ||
542 | * on tests. Ignore it too. | ||
543 | */ | ||
544 | goto traps_done; | ||
545 | } else if ((fp->rets >= (L1_CODE_START + L1_CODE_LENGTH - 512)) && | ||
546 | (fp->rets < (L1_CODE_START + L1_CODE_LENGTH))) { | ||
547 | /* | ||
548 | * If boundary code calls a function, at the entry point, | ||
549 | * a new false hardware error maybe happen based on tests. | ||
550 | * Ignore it too. | ||
551 | */ | ||
552 | goto traps_done; | ||
553 | } else | ||
554 | anomaly_rets = 0; | ||
555 | } | ||
556 | |||
541 | info.si_code = BUS_ADRERR; | 557 | info.si_code = BUS_ADRERR; |
542 | sig = SIGBUS; | 558 | sig = SIGBUS; |
543 | strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); | 559 | strerror = KERN_NOTICE HWC_x3(KERN_NOTICE); |
@@ -642,7 +658,7 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
642 | 658 | ||
643 | /* | 659 | /* |
644 | * Similar to get_user, do some address checking, then dereference | 660 | * Similar to get_user, do some address checking, then dereference |
645 | * Return true on sucess, false on bad address | 661 | * Return true on success, false on bad address |
646 | */ | 662 | */ |
647 | static bool get_instruction(unsigned short *val, unsigned short *address) | 663 | static bool get_instruction(unsigned short *val, unsigned short *address) |
648 | { | 664 | { |
@@ -999,12 +1015,12 @@ void dump_bfin_process(struct pt_regs *fp) | |||
999 | !((unsigned long)current & 0x3) && current->pid) { | 1015 | !((unsigned long)current & 0x3) && current->pid) { |
1000 | verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); | 1016 | verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); |
1001 | if (current->comm >= (char *)FIXED_CODE_START) | 1017 | if (current->comm >= (char *)FIXED_CODE_START) |
1002 | verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n", | 1018 | verbose_printk(KERN_NOTICE "COMM=%s PID=%d", |
1003 | current->comm, current->pid); | 1019 | current->comm, current->pid); |
1004 | else | 1020 | else |
1005 | verbose_printk(KERN_NOTICE "COMM= invalid\n"); | 1021 | verbose_printk(KERN_NOTICE "COMM= invalid"); |
1006 | 1022 | ||
1007 | printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu); | 1023 | printk(KERN_CONT " CPU=%d\n", current_thread_info()->cpu); |
1008 | if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) | 1024 | if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) |
1009 | verbose_printk(KERN_NOTICE | 1025 | verbose_printk(KERN_NOTICE |
1010 | "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" | 1026 | "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" |
@@ -1163,7 +1179,7 @@ void show_regs(struct pt_regs *fp) | |||
1163 | if (fp->ipend & ~0x3F) { | 1179 | if (fp->ipend & ~0x3F) { |
1164 | for (i = 0; i < (NR_IRQS - 1); i++) { | 1180 | for (i = 0; i < (NR_IRQS - 1); i++) { |
1165 | if (!in_atomic) | 1181 | if (!in_atomic) |
1166 | spin_lock_irqsave(&irq_desc[i].lock, flags); | 1182 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); |
1167 | 1183 | ||
1168 | action = irq_desc[i].action; | 1184 | action = irq_desc[i].action; |
1169 | if (!action) | 1185 | if (!action) |
@@ -1178,7 +1194,7 @@ void show_regs(struct pt_regs *fp) | |||
1178 | verbose_printk("\n"); | 1194 | verbose_printk("\n"); |
1179 | unlock: | 1195 | unlock: |
1180 | if (!in_atomic) | 1196 | if (!in_atomic) |
1181 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); | 1197 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); |
1182 | } | 1198 | } |
1183 | } | 1199 | } |
1184 | 1200 | ||