diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 110 |
1 files changed, 95 insertions, 15 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 792a8416fe10..8823e9ade584 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c | |||
@@ -51,10 +51,9 @@ void __init trap_init(void) | |||
51 | CSYNC(); | 51 | CSYNC(); |
52 | } | 52 | } |
53 | 53 | ||
54 | asmlinkage void trap_c(struct pt_regs *fp); | ||
55 | |||
56 | int kstack_depth_to_print = 48; | 54 | int kstack_depth_to_print = 48; |
57 | 55 | ||
56 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
58 | static int printk_address(unsigned long address) | 57 | static int printk_address(unsigned long address) |
59 | { | 58 | { |
60 | struct vm_list_struct *vml; | 59 | struct vm_list_struct *vml; |
@@ -131,10 +130,22 @@ static int printk_address(unsigned long address) | |||
131 | /* we were unable to find this address anywhere */ | 130 | /* we were unable to find this address anywhere */ |
132 | return printk("[<0x%p>]", (void *)address); | 131 | return printk("[<0x%p>]", (void *)address); |
133 | } | 132 | } |
133 | #endif | ||
134 | |||
135 | asmlinkage void double_fault_c(struct pt_regs *fp) | ||
136 | { | ||
137 | printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); | ||
138 | dump_bfin_regs(fp, (void *)fp->retx); | ||
139 | panic("Double Fault - unrecoverable event\n"); | ||
140 | |||
141 | } | ||
134 | 142 | ||
135 | asmlinkage void trap_c(struct pt_regs *fp) | 143 | asmlinkage void trap_c(struct pt_regs *fp) |
136 | { | 144 | { |
137 | int j, sig = 0; | 145 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
146 | int j; | ||
147 | #endif | ||
148 | int sig = 0; | ||
138 | siginfo_t info; | 149 | siginfo_t info; |
139 | unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; | 150 | unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; |
140 | 151 | ||
@@ -391,10 +402,6 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
391 | break; | 402 | break; |
392 | } | 403 | } |
393 | 404 | ||
394 | info.si_signo = sig; | ||
395 | info.si_errno = 0; | ||
396 | info.si_addr = (void *)fp->pc; | ||
397 | force_sig_info(sig, &info, current); | ||
398 | if (sig != 0 && sig != SIGTRAP) { | 405 | if (sig != 0 && sig != SIGTRAP) { |
399 | unsigned long stack; | 406 | unsigned long stack; |
400 | dump_bfin_regs(fp, (void *)fp->retx); | 407 | dump_bfin_regs(fp, (void *)fp->retx); |
@@ -403,6 +410,10 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
403 | if (current->mm == NULL) | 410 | if (current->mm == NULL) |
404 | panic("Kernel exception"); | 411 | panic("Kernel exception"); |
405 | } | 412 | } |
413 | info.si_signo = sig; | ||
414 | info.si_errno = 0; | ||
415 | info.si_addr = (void *)fp->pc; | ||
416 | force_sig_info(sig, &info, current); | ||
406 | 417 | ||
407 | /* if the address that we are about to return to is not valid, set it | 418 | /* if the address that we are about to return to is not valid, set it |
408 | * to a valid address, if we have a current application or panic | 419 | * to a valid address, if we have a current application or panic |
@@ -429,24 +440,56 @@ asmlinkage void trap_c(struct pt_regs *fp) | |||
429 | 440 | ||
430 | /* Typical exception handling routines */ | 441 | /* Typical exception handling routines */ |
431 | 442 | ||
443 | #define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1) | ||
444 | |||
432 | void dump_bfin_trace_buffer(void) | 445 | void dump_bfin_trace_buffer(void) |
433 | { | 446 | { |
434 | int tflags; | 447 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
448 | int tflags, i = 0; | ||
449 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
450 | int j, index; | ||
451 | #endif | ||
452 | |||
435 | trace_buffer_save(tflags); | 453 | trace_buffer_save(tflags); |
436 | 454 | ||
455 | printk(KERN_EMERG "Hardware Trace:\n"); | ||
456 | |||
437 | if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { | 457 | if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { |
438 | int i; | 458 | for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) { |
439 | printk(KERN_EMERG "Hardware Trace:\n"); | 459 | printk(KERN_EMERG "%4i Target : ", i); |
440 | for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) { | ||
441 | printk(KERN_EMERG "%2i Target : ", i); | ||
442 | printk_address((unsigned long)bfin_read_TBUF()); | 460 | printk_address((unsigned long)bfin_read_TBUF()); |
443 | printk("\n" KERN_EMERG " Source : "); | 461 | printk("\n" KERN_EMERG " Source : "); |
444 | printk_address((unsigned long)bfin_read_TBUF()); | 462 | printk_address((unsigned long)bfin_read_TBUF()); |
445 | printk("\n"); | 463 | printk("\n"); |
446 | } | 464 | } |
447 | } | 465 | } |
448 | 466 | ||
467 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
468 | if (trace_buff_offset) | ||
469 | index = trace_buff_offset/4 - 1; | ||
470 | else | ||
471 | index = EXPAND_LEN; | ||
472 | |||
473 | j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128; | ||
474 | while (j) { | ||
475 | printk(KERN_EMERG "%4i Target : ", i); | ||
476 | printk_address(software_trace_buff[index]); | ||
477 | index -= 1; | ||
478 | if (index < 0 ) | ||
479 | index = EXPAND_LEN; | ||
480 | printk("\n" KERN_EMERG " Source : "); | ||
481 | printk_address(software_trace_buff[index]); | ||
482 | index -= 1; | ||
483 | if (index < 0) | ||
484 | index = EXPAND_LEN; | ||
485 | printk("\n"); | ||
486 | j--; | ||
487 | i++; | ||
488 | } | ||
489 | #endif | ||
490 | |||
449 | trace_buffer_restore(tflags); | 491 | trace_buffer_restore(tflags); |
492 | #endif | ||
450 | } | 493 | } |
451 | EXPORT_SYMBOL(dump_bfin_trace_buffer); | 494 | EXPORT_SYMBOL(dump_bfin_trace_buffer); |
452 | 495 | ||
@@ -510,7 +553,9 @@ void show_stack(struct task_struct *task, unsigned long *stack) | |||
510 | void dump_stack(void) | 553 | void dump_stack(void) |
511 | { | 554 | { |
512 | unsigned long stack; | 555 | unsigned long stack; |
556 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
513 | int tflags; | 557 | int tflags; |
558 | #endif | ||
514 | trace_buffer_save(tflags); | 559 | trace_buffer_save(tflags); |
515 | dump_bfin_trace_buffer(); | 560 | dump_bfin_trace_buffer(); |
516 | show_stack(current, &stack); | 561 | show_stack(current, &stack); |
@@ -559,8 +604,7 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr) | |||
559 | unsigned short x = 0; | 604 | unsigned short x = 0; |
560 | for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) { | 605 | for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) { |
561 | if (!(i & 0xF)) | 606 | if (!(i & 0xF)) |
562 | printk(KERN_EMERG "\n" KERN_EMERG | 607 | printk("\n" KERN_EMERG "0x%08x: ", i); |
563 | "0x%08x: ", i); | ||
564 | 608 | ||
565 | if (get_user(x, (unsigned short *)i)) | 609 | if (get_user(x, (unsigned short *)i)) |
566 | break; | 610 | break; |
@@ -655,6 +699,42 @@ asmlinkage int sys_bfin_spinlock(int *spinlock) | |||
655 | return ret; | 699 | return ret; |
656 | } | 700 | } |
657 | 701 | ||
702 | int bfin_request_exception(unsigned int exception, void (*handler)(void)) | ||
703 | { | ||
704 | void (*curr_handler)(void); | ||
705 | |||
706 | if (exception > 0x3F) | ||
707 | return -EINVAL; | ||
708 | |||
709 | curr_handler = ex_table[exception]; | ||
710 | |||
711 | if (curr_handler != ex_replaceable) | ||
712 | return -EBUSY; | ||
713 | |||
714 | ex_table[exception] = handler; | ||
715 | |||
716 | return 0; | ||
717 | } | ||
718 | EXPORT_SYMBOL(bfin_request_exception); | ||
719 | |||
720 | int bfin_free_exception(unsigned int exception, void (*handler)(void)) | ||
721 | { | ||
722 | void (*curr_handler)(void); | ||
723 | |||
724 | if (exception > 0x3F) | ||
725 | return -EINVAL; | ||
726 | |||
727 | curr_handler = ex_table[exception]; | ||
728 | |||
729 | if (curr_handler != handler) | ||
730 | return -EBUSY; | ||
731 | |||
732 | ex_table[exception] = ex_replaceable; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | EXPORT_SYMBOL(bfin_free_exception); | ||
737 | |||
658 | void panic_cplb_error(int cplb_panic, struct pt_regs *fp) | 738 | void panic_cplb_error(int cplb_panic, struct pt_regs *fp) |
659 | { | 739 | { |
660 | switch (cplb_panic) { | 740 | switch (cplb_panic) { |