diff options
Diffstat (limited to 'arch/blackfin/kernel')
| -rw-r--r-- | arch/blackfin/kernel/Makefile | 5 | ||||
| -rw-r--r-- | arch/blackfin/kernel/bfin_gpio.c | 131 | ||||
| -rw-r--r-- | arch/blackfin/kernel/bfin_ksyms.c | 12 | ||||
| -rw-r--r-- | arch/blackfin/kernel/dumpstack.c | 174 | ||||
| -rw-r--r-- | arch/blackfin/kernel/exception.c | 45 | ||||
| -rw-r--r-- | arch/blackfin/kernel/kgdb.c | 2 | ||||
| -rw-r--r-- | arch/blackfin/kernel/pseudodbg.c | 191 | ||||
| -rw-r--r-- | arch/blackfin/kernel/setup.c | 4 | ||||
| -rw-r--r-- | arch/blackfin/kernel/sys_bfin.c | 23 | ||||
| -rw-r--r-- | arch/blackfin/kernel/trace.c | 981 | ||||
| -rw-r--r-- | arch/blackfin/kernel/traps.c | 900 |
11 files changed, 1510 insertions, 958 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index 346a421f1562..30d0d1f01dc7 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile | |||
| @@ -7,7 +7,8 @@ extra-y := init_task.o vmlinux.lds | |||
| 7 | obj-y := \ | 7 | obj-y := \ |
| 8 | entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ | 8 | entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ |
| 9 | sys_bfin.o traps.o irqchip.o dma-mapping.o flat.o \ | 9 | sys_bfin.o traps.o irqchip.o dma-mapping.o flat.o \ |
| 10 | fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o | 10 | fixed_code.o reboot.o bfin_gpio.o bfin_dma_5xx.o \ |
| 11 | exception.o dumpstack.o | ||
| 11 | 12 | ||
| 12 | ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y) | 13 | ifeq ($(CONFIG_GENERIC_CLOCKEVENTS),y) |
| 13 | obj-y += time-ts.o | 14 | obj-y += time-ts.o |
| @@ -29,6 +30,8 @@ obj-$(CONFIG_NMI_WATCHDOG) += nmi.o | |||
| 29 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 30 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 30 | obj-$(CONFIG_EARLY_PRINTK) += shadow_console.o | 31 | obj-$(CONFIG_EARLY_PRINTK) += shadow_console.o |
| 31 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 32 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
| 33 | obj-$(CONFIG_DEBUG_VERBOSE) += trace.o | ||
| 34 | obj-$(CONFIG_BFIN_PSEUDODBG_INSNS) += pseudodbg.o | ||
| 32 | 35 | ||
| 33 | # the kgdb test puts code into L2 and without linker | 36 | # the kgdb test puts code into L2 and without linker |
| 34 | # relaxation, we need to force long calls to/from it | 37 | # relaxation, we need to force long calls to/from it |
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index e35e20f00d9b..42833ee2b308 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c | |||
| @@ -475,9 +475,7 @@ GET_GPIO_P(maskb) | |||
| 475 | 475 | ||
| 476 | 476 | ||
| 477 | #ifdef CONFIG_PM | 477 | #ifdef CONFIG_PM |
| 478 | |||
| 479 | static unsigned short wakeup_map[GPIO_BANK_NUM]; | 478 | static unsigned short wakeup_map[GPIO_BANK_NUM]; |
| 480 | static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS]; | ||
| 481 | 479 | ||
| 482 | static const unsigned int sic_iwr_irqs[] = { | 480 | static const unsigned int sic_iwr_irqs[] = { |
| 483 | #if defined(BF533_FAMILY) | 481 | #if defined(BF533_FAMILY) |
| @@ -514,112 +512,26 @@ static const unsigned int sic_iwr_irqs[] = { | |||
| 514 | ************************************************************* | 512 | ************************************************************* |
| 515 | * MODIFICATION HISTORY : | 513 | * MODIFICATION HISTORY : |
| 516 | **************************************************************/ | 514 | **************************************************************/ |
| 517 | int gpio_pm_wakeup_request(unsigned gpio, unsigned char type) | 515 | int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl) |
| 518 | { | ||
| 519 | unsigned long flags; | ||
| 520 | |||
| 521 | if ((check_gpio(gpio) < 0) || !type) | ||
| 522 | return -EINVAL; | ||
| 523 | |||
| 524 | local_irq_save_hw(flags); | ||
| 525 | wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio); | ||
| 526 | wakeup_flags_map[gpio] = type; | ||
| 527 | local_irq_restore_hw(flags); | ||
| 528 | |||
| 529 | return 0; | ||
| 530 | } | ||
| 531 | EXPORT_SYMBOL(gpio_pm_wakeup_request); | ||
| 532 | |||
| 533 | void gpio_pm_wakeup_free(unsigned gpio) | ||
| 534 | { | 516 | { |
| 535 | unsigned long flags; | 517 | unsigned long flags; |
| 536 | 518 | ||
| 537 | if (check_gpio(gpio) < 0) | 519 | if (check_gpio(gpio) < 0) |
| 538 | return; | 520 | return -EINVAL; |
| 539 | 521 | ||
| 540 | local_irq_save_hw(flags); | 522 | local_irq_save_hw(flags); |
| 541 | 523 | if (ctrl) | |
| 542 | wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); | 524 | wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio); |
| 543 | |||
| 544 | local_irq_restore_hw(flags); | ||
| 545 | } | ||
| 546 | EXPORT_SYMBOL(gpio_pm_wakeup_free); | ||
| 547 | |||
| 548 | static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type) | ||
| 549 | { | ||
| 550 | port_setup(gpio, GPIO_USAGE); | ||
| 551 | set_gpio_dir(gpio, 0); | ||
| 552 | set_gpio_inen(gpio, 1); | ||
| 553 | |||
| 554 | if (type & (PM_WAKE_RISING | PM_WAKE_FALLING)) | ||
| 555 | set_gpio_edge(gpio, 1); | ||
| 556 | else | ||
| 557 | set_gpio_edge(gpio, 0); | ||
| 558 | |||
| 559 | if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES)) | ||
| 560 | set_gpio_both(gpio, 1); | ||
| 561 | else | 525 | else |
| 562 | set_gpio_both(gpio, 0); | 526 | wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); |
| 563 | |||
| 564 | if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW))) | ||
| 565 | set_gpio_polar(gpio, 1); | ||
| 566 | else | ||
| 567 | set_gpio_polar(gpio, 0); | ||
| 568 | 527 | ||
| 569 | SSYNC(); | 528 | set_gpio_maskb(gpio, ctrl); |
| 570 | 529 | local_irq_restore_hw(flags); | |
| 571 | return 0; | ||
| 572 | } | ||
| 573 | |||
| 574 | u32 bfin_pm_standby_setup(void) | ||
| 575 | { | ||
| 576 | u16 bank, mask, i, gpio; | ||
| 577 | |||
| 578 | for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { | ||
| 579 | mask = wakeup_map[gpio_bank(i)]; | ||
| 580 | bank = gpio_bank(i); | ||
| 581 | |||
| 582 | gpio_bank_saved[bank].maskb = gpio_array[bank]->maskb; | ||
| 583 | gpio_array[bank]->maskb = 0; | ||
| 584 | |||
| 585 | if (mask) { | ||
| 586 | #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) | ||
| 587 | gpio_bank_saved[bank].fer = *port_fer[bank]; | ||
| 588 | #endif | ||
| 589 | gpio_bank_saved[bank].inen = gpio_array[bank]->inen; | ||
| 590 | gpio_bank_saved[bank].polar = gpio_array[bank]->polar; | ||
| 591 | gpio_bank_saved[bank].dir = gpio_array[bank]->dir; | ||
| 592 | gpio_bank_saved[bank].edge = gpio_array[bank]->edge; | ||
| 593 | gpio_bank_saved[bank].both = gpio_array[bank]->both; | ||
| 594 | gpio_bank_saved[bank].reserved = | ||
| 595 | reserved_gpio_map[bank]; | ||
| 596 | |||
| 597 | gpio = i; | ||
| 598 | |||
| 599 | while (mask) { | ||
| 600 | if ((mask & 1) && (wakeup_flags_map[gpio] != | ||
| 601 | PM_WAKE_IGNORE)) { | ||
| 602 | reserved_gpio_map[gpio_bank(gpio)] |= | ||
| 603 | gpio_bit(gpio); | ||
| 604 | bfin_gpio_wakeup_type(gpio, | ||
| 605 | wakeup_flags_map[gpio]); | ||
| 606 | set_gpio_data(gpio, 0); /*Clear*/ | ||
| 607 | } | ||
| 608 | gpio++; | ||
| 609 | mask >>= 1; | ||
| 610 | } | ||
| 611 | |||
| 612 | bfin_internal_set_wake(sic_iwr_irqs[bank], 1); | ||
| 613 | gpio_array[bank]->maskb_set = wakeup_map[gpio_bank(i)]; | ||
| 614 | } | ||
| 615 | } | ||
| 616 | |||
| 617 | AWA_DUMMY_READ(maskb_set); | ||
| 618 | 530 | ||
| 619 | return 0; | 531 | return 0; |
| 620 | } | 532 | } |
| 621 | 533 | ||
| 622 | void bfin_pm_standby_restore(void) | 534 | int bfin_pm_standby_ctrl(unsigned ctrl) |
| 623 | { | 535 | { |
| 624 | u16 bank, mask, i; | 536 | u16 bank, mask, i; |
| 625 | 537 | ||
| @@ -627,24 +539,10 @@ void bfin_pm_standby_restore(void) | |||
| 627 | mask = wakeup_map[gpio_bank(i)]; | 539 | mask = wakeup_map[gpio_bank(i)]; |
| 628 | bank = gpio_bank(i); | 540 | bank = gpio_bank(i); |
| 629 | 541 | ||
| 630 | if (mask) { | 542 | if (mask) |
| 631 | #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) | 543 | bfin_internal_set_wake(sic_iwr_irqs[bank], ctrl); |
| 632 | *port_fer[bank] = gpio_bank_saved[bank].fer; | ||
| 633 | #endif | ||
| 634 | gpio_array[bank]->inen = gpio_bank_saved[bank].inen; | ||
| 635 | gpio_array[bank]->dir = gpio_bank_saved[bank].dir; | ||
| 636 | gpio_array[bank]->polar = gpio_bank_saved[bank].polar; | ||
| 637 | gpio_array[bank]->edge = gpio_bank_saved[bank].edge; | ||
| 638 | gpio_array[bank]->both = gpio_bank_saved[bank].both; | ||
| 639 | |||
| 640 | reserved_gpio_map[bank] = | ||
| 641 | gpio_bank_saved[bank].reserved; | ||
| 642 | bfin_internal_set_wake(sic_iwr_irqs[bank], 0); | ||
| 643 | } | ||
| 644 | |||
| 645 | gpio_array[bank]->maskb = gpio_bank_saved[bank].maskb; | ||
| 646 | } | 544 | } |
| 647 | AWA_DUMMY_READ(maskb); | 545 | return 0; |
| 648 | } | 546 | } |
| 649 | 547 | ||
| 650 | void bfin_gpio_pm_hibernate_suspend(void) | 548 | void bfin_gpio_pm_hibernate_suspend(void) |
| @@ -708,16 +606,11 @@ void bfin_gpio_pm_hibernate_restore(void) | |||
| 708 | #else /* CONFIG_BF54x */ | 606 | #else /* CONFIG_BF54x */ |
| 709 | #ifdef CONFIG_PM | 607 | #ifdef CONFIG_PM |
| 710 | 608 | ||
| 711 | u32 bfin_pm_standby_setup(void) | 609 | int bfin_pm_standby_ctrl(unsigned ctrl) |
| 712 | { | 610 | { |
| 713 | return 0; | 611 | return 0; |
| 714 | } | 612 | } |
| 715 | 613 | ||
| 716 | void bfin_pm_standby_restore(void) | ||
| 717 | { | ||
| 718 | |||
| 719 | } | ||
| 720 | |||
| 721 | void bfin_gpio_pm_hibernate_suspend(void) | 614 | void bfin_gpio_pm_hibernate_suspend(void) |
| 722 | { | 615 | { |
| 723 | int i, bank; | 616 | int i, bank; |
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index ed8392c117ea..2c264b51566a 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c | |||
| @@ -33,6 +33,18 @@ EXPORT_SYMBOL(memmove); | |||
| 33 | EXPORT_SYMBOL(memchr); | 33 | EXPORT_SYMBOL(memchr); |
| 34 | 34 | ||
| 35 | /* | 35 | /* |
| 36 | * Because string functions are both inline and exported functions and | ||
| 37 | * folder arch/blackfin/lib is configured as a library path in Makefile, | ||
| 38 | * symbols exported in folder lib is not linked into built-in.o but | ||
| 39 | * inlined only. In order to export string symbols to kernel module | ||
| 40 | * properly, they should be exported here. | ||
| 41 | */ | ||
| 42 | EXPORT_SYMBOL(strcpy); | ||
| 43 | EXPORT_SYMBOL(strncpy); | ||
| 44 | EXPORT_SYMBOL(strcmp); | ||
| 45 | EXPORT_SYMBOL(strncmp); | ||
| 46 | |||
| 47 | /* | ||
| 36 | * libgcc functions - functions that are used internally by the | 48 | * libgcc functions - functions that are used internally by the |
| 37 | * compiler... (prototypes are not correct though, but that | 49 | * compiler... (prototypes are not correct though, but that |
| 38 | * doesn't really matter since they're not versioned). | 50 | * doesn't really matter since they're not versioned). |
diff --git a/arch/blackfin/kernel/dumpstack.c b/arch/blackfin/kernel/dumpstack.c new file mode 100644 index 000000000000..5cfbaa298211 --- /dev/null +++ b/arch/blackfin/kernel/dumpstack.c | |||
| @@ -0,0 +1,174 @@ | |||
| 1 | /* Provide basic stack dumping functions | ||
| 2 | * | ||
| 3 | * Copyright 2004-2009 Analog Devices Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the GPL-2 or later | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/thread_info.h> | ||
| 10 | #include <linux/mm.h> | ||
| 11 | #include <linux/uaccess.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <asm/trace.h> | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Checks to see if the address pointed to is either a | ||
| 17 | * 16-bit CALL instruction, or a 32-bit CALL instruction | ||
| 18 | */ | ||
| 19 | static bool is_bfin_call(unsigned short *addr) | ||
| 20 | { | ||
| 21 | unsigned int opcode; | ||
| 22 | |||
| 23 | if (!get_instruction(&opcode, addr)) | ||
| 24 | return false; | ||
| 25 | |||
| 26 | if ((opcode >= 0x0060 && opcode <= 0x0067) || | ||
| 27 | (opcode >= 0x0070 && opcode <= 0x0077) || | ||
| 28 | (opcode >= 0xE3000000 && opcode <= 0xE3FFFFFF)) | ||
| 29 | return true; | ||
| 30 | |||
| 31 | return false; | ||
| 32 | |||
| 33 | } | ||
| 34 | |||
| 35 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
| 36 | { | ||
| 37 | #ifdef CONFIG_PRINTK | ||
| 38 | unsigned int *addr, *endstack, *fp = 0, *frame; | ||
| 39 | unsigned short *ins_addr; | ||
| 40 | char buf[150]; | ||
| 41 | unsigned int i, j, ret_addr, frame_no = 0; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * If we have been passed a specific stack, use that one otherwise | ||
| 45 | * if we have been passed a task structure, use that, otherwise | ||
| 46 | * use the stack of where the variable "stack" exists | ||
| 47 | */ | ||
| 48 | |||
| 49 | if (stack == NULL) { | ||
| 50 | if (task) { | ||
| 51 | /* We know this is a kernel stack, so this is the start/end */ | ||
| 52 | stack = (unsigned long *)task->thread.ksp; | ||
| 53 | endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE); | ||
| 54 | } else { | ||
| 55 | /* print out the existing stack info */ | ||
| 56 | stack = (unsigned long *)&stack; | ||
| 57 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | ||
| 58 | } | ||
| 59 | } else | ||
| 60 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | ||
| 61 | |||
| 62 | printk(KERN_NOTICE "Stack info:\n"); | ||
| 63 | decode_address(buf, (unsigned int)stack); | ||
| 64 | printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); | ||
| 65 | |||
| 66 | if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) { | ||
| 67 | printk(KERN_NOTICE "Invalid stack pointer\n"); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | |||
| 71 | /* First thing is to look for a frame pointer */ | ||
| 72 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) { | ||
| 73 | if (*addr & 0x1) | ||
| 74 | continue; | ||
| 75 | ins_addr = (unsigned short *)*addr; | ||
| 76 | ins_addr--; | ||
| 77 | if (is_bfin_call(ins_addr)) | ||
| 78 | fp = addr - 1; | ||
| 79 | |||
| 80 | if (fp) { | ||
| 81 | /* Let's check to see if it is a frame pointer */ | ||
| 82 | while (fp >= (addr - 1) && fp < endstack | ||
| 83 | && fp && ((unsigned int) fp & 0x3) == 0) | ||
| 84 | fp = (unsigned int *)*fp; | ||
| 85 | if (fp == 0 || fp == endstack) { | ||
| 86 | fp = addr - 1; | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | fp = 0; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | if (fp) { | ||
| 93 | frame = fp; | ||
| 94 | printk(KERN_NOTICE " FP: (0x%p)\n", fp); | ||
| 95 | } else | ||
| 96 | frame = 0; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Now that we think we know where things are, we | ||
| 100 | * walk the stack again, this time printing things out | ||
| 101 | * incase there is no frame pointer, we still look for | ||
| 102 | * valid return addresses | ||
| 103 | */ | ||
| 104 | |||
| 105 | /* First time print out data, next time, print out symbols */ | ||
| 106 | for (j = 0; j <= 1; j++) { | ||
| 107 | if (j) | ||
| 108 | printk(KERN_NOTICE "Return addresses in stack:\n"); | ||
| 109 | else | ||
| 110 | printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack); | ||
| 111 | |||
| 112 | fp = frame; | ||
| 113 | frame_no = 0; | ||
| 114 | |||
| 115 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0; | ||
| 116 | addr < endstack; addr++, i++) { | ||
| 117 | |||
| 118 | ret_addr = 0; | ||
| 119 | if (!j && i % 8 == 0) | ||
| 120 | printk(KERN_NOTICE "%p:", addr); | ||
| 121 | |||
| 122 | /* if it is an odd address, or zero, just skip it */ | ||
| 123 | if (*addr & 0x1 || !*addr) | ||
| 124 | goto print; | ||
| 125 | |||
| 126 | ins_addr = (unsigned short *)*addr; | ||
| 127 | |||
| 128 | /* Go back one instruction, and see if it is a CALL */ | ||
| 129 | ins_addr--; | ||
| 130 | ret_addr = is_bfin_call(ins_addr); | ||
| 131 | print: | ||
| 132 | if (!j && stack == (unsigned long *)addr) | ||
| 133 | printk("[%08x]", *addr); | ||
| 134 | else if (ret_addr) | ||
| 135 | if (j) { | ||
| 136 | decode_address(buf, (unsigned int)*addr); | ||
| 137 | if (frame == addr) { | ||
| 138 | printk(KERN_NOTICE " frame %2i : %s\n", frame_no, buf); | ||
| 139 | continue; | ||
| 140 | } | ||
| 141 | printk(KERN_NOTICE " address : %s\n", buf); | ||
| 142 | } else | ||
| 143 | printk("<%08x>", *addr); | ||
| 144 | else if (fp == addr) { | ||
| 145 | if (j) | ||
| 146 | frame = addr+1; | ||
| 147 | else | ||
| 148 | printk("(%08x)", *addr); | ||
| 149 | |||
| 150 | fp = (unsigned int *)*addr; | ||
| 151 | frame_no++; | ||
| 152 | |||
| 153 | } else if (!j) | ||
| 154 | printk(" %08x ", *addr); | ||
| 155 | } | ||
| 156 | if (!j) | ||
| 157 | printk("\n"); | ||
| 158 | } | ||
| 159 | #endif | ||
| 160 | } | ||
| 161 | EXPORT_SYMBOL(show_stack); | ||
| 162 | |||
| 163 | void dump_stack(void) | ||
| 164 | { | ||
| 165 | unsigned long stack; | ||
| 166 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
| 167 | int tflags; | ||
| 168 | #endif | ||
| 169 | trace_buffer_save(tflags); | ||
| 170 | dump_bfin_trace_buffer(); | ||
| 171 | show_stack(current, &stack); | ||
| 172 | trace_buffer_restore(tflags); | ||
| 173 | } | ||
| 174 | EXPORT_SYMBOL(dump_stack); | ||
diff --git a/arch/blackfin/kernel/exception.c b/arch/blackfin/kernel/exception.c new file mode 100644 index 000000000000..9208b5fd5186 --- /dev/null +++ b/arch/blackfin/kernel/exception.c | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* Basic functions for adding/removing custom exception handlers | ||
| 2 | * | ||
| 3 | * Copyright 2004-2009 Analog Devices Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the GPL-2 or later | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/module.h> | ||
| 9 | #include <asm/irq_handler.h> | ||
| 10 | |||
| 11 | int bfin_request_exception(unsigned int exception, void (*handler)(void)) | ||
| 12 | { | ||
| 13 | void (*curr_handler)(void); | ||
| 14 | |||
| 15 | if (exception > 0x3F) | ||
| 16 | return -EINVAL; | ||
| 17 | |||
| 18 | curr_handler = ex_table[exception]; | ||
| 19 | |||
| 20 | if (curr_handler != ex_replaceable) | ||
| 21 | return -EBUSY; | ||
| 22 | |||
| 23 | ex_table[exception] = handler; | ||
| 24 | |||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | EXPORT_SYMBOL(bfin_request_exception); | ||
| 28 | |||
| 29 | int bfin_free_exception(unsigned int exception, void (*handler)(void)) | ||
| 30 | { | ||
| 31 | void (*curr_handler)(void); | ||
| 32 | |||
| 33 | if (exception > 0x3F) | ||
| 34 | return -EINVAL; | ||
| 35 | |||
| 36 | curr_handler = ex_table[exception]; | ||
| 37 | |||
| 38 | if (curr_handler != handler) | ||
| 39 | return -EBUSY; | ||
| 40 | |||
| 41 | ex_table[exception] = ex_replaceable; | ||
| 42 | |||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | EXPORT_SYMBOL(bfin_free_exception); | ||
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index 7367aea4ae59..08bc44ea6883 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c | |||
| @@ -66,7 +66,7 @@ void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
| 66 | gdb_regs[BFIN_RETN] = regs->retn; | 66 | gdb_regs[BFIN_RETN] = regs->retn; |
| 67 | gdb_regs[BFIN_RETE] = regs->rete; | 67 | gdb_regs[BFIN_RETE] = regs->rete; |
| 68 | gdb_regs[BFIN_PC] = regs->pc; | 68 | gdb_regs[BFIN_PC] = regs->pc; |
| 69 | gdb_regs[BFIN_CC] = 0; | 69 | gdb_regs[BFIN_CC] = (regs->astat >> 5) & 1; |
| 70 | gdb_regs[BFIN_EXTRA1] = 0; | 70 | gdb_regs[BFIN_EXTRA1] = 0; |
| 71 | gdb_regs[BFIN_EXTRA2] = 0; | 71 | gdb_regs[BFIN_EXTRA2] = 0; |
| 72 | gdb_regs[BFIN_EXTRA3] = 0; | 72 | gdb_regs[BFIN_EXTRA3] = 0; |
diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c new file mode 100644 index 000000000000..db85bc94334e --- /dev/null +++ b/arch/blackfin/kernel/pseudodbg.c | |||
| @@ -0,0 +1,191 @@ | |||
| 1 | /* The fake debug assert instructions | ||
| 2 | * | ||
| 3 | * Copyright 2010 Analog Devices Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the GPL-2 or later | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/types.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/ptrace.h> | ||
| 11 | |||
| 12 | const char * const greg_names[] = { | ||
| 13 | "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", | ||
| 14 | "P0", "P1", "P2", "P3", "P4", "P5", "SP", "FP", | ||
| 15 | "I0", "I1", "I2", "I3", "M0", "M1", "M2", "M3", | ||
| 16 | "B0", "B1", "B2", "B3", "L0", "L1", "L2", "L3", | ||
| 17 | "A0.X", "A0.W", "A1.X", "A1.W", "<res>", "<res>", "ASTAT", "RETS", | ||
| 18 | "<res>", "<res>", "<res>", "<res>", "<res>", "<res>", "<res>", "<res>", | ||
| 19 | "LC0", "LT0", "LB0", "LC1", "LT1", "LB1", "CYCLES", "CYCLES2", | ||
| 20 | "USP", "SEQSTAT", "SYSCFG", "RETI", "RETX", "RETN", "RETE", "EMUDAT", | ||
| 21 | }; | ||
| 22 | |||
| 23 | static const char *get_allreg_name(int grp, int reg) | ||
| 24 | { | ||
| 25 | return greg_names[(grp << 3) | reg]; | ||
| 26 | } | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Unfortunately, the pt_regs structure is not laid out the same way as the | ||
| 30 | * hardware register file, so we need to do some fix ups. | ||
| 31 | * | ||
| 32 | * CYCLES is not stored in the pt_regs structure - so, we just read it from | ||
| 33 | * the hardware. | ||
| 34 | * | ||
| 35 | * Don't support: | ||
| 36 | * - All reserved registers | ||
| 37 | * - All in group 7 are (supervisors only) | ||
| 38 | */ | ||
| 39 | |||
| 40 | static bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg) | ||
| 41 | { | ||
| 42 | long *val = &fp->r0; | ||
| 43 | unsigned long tmp; | ||
| 44 | |||
| 45 | /* Only do Dregs and Pregs for now */ | ||
| 46 | if (grp == 5 || | ||
| 47 | (grp == 4 && (reg == 4 || reg == 5)) || | ||
| 48 | (grp == 7)) | ||
| 49 | return false; | ||
| 50 | |||
| 51 | if (grp == 0 || (grp == 1 && reg < 6)) | ||
| 52 | val -= (reg + 8 * grp); | ||
| 53 | else if (grp == 1 && reg == 6) | ||
| 54 | val = &fp->usp; | ||
| 55 | else if (grp == 1 && reg == 7) | ||
| 56 | val = &fp->fp; | ||
| 57 | else if (grp == 2) { | ||
| 58 | val = &fp->i0; | ||
| 59 | val -= reg; | ||
| 60 | } else if (grp == 3 && reg >= 4) { | ||
| 61 | val = &fp->l0; | ||
| 62 | val -= (reg - 4); | ||
| 63 | } else if (grp == 3 && reg < 4) { | ||
| 64 | val = &fp->b0; | ||
| 65 | val -= reg; | ||
| 66 | } else if (grp == 4 && reg < 4) { | ||
| 67 | val = &fp->a0x; | ||
| 68 | val -= reg; | ||
| 69 | } else if (grp == 4 && reg == 6) | ||
| 70 | val = &fp->astat; | ||
| 71 | else if (grp == 4 && reg == 7) | ||
| 72 | val = &fp->rets; | ||
| 73 | else if (grp == 6 && reg < 6) { | ||
| 74 | val = &fp->lc0; | ||
| 75 | val -= reg; | ||
| 76 | } else if (grp == 6 && reg == 6) { | ||
| 77 | __asm__ __volatile__("%0 = cycles;\n" : "=d"(tmp)); | ||
| 78 | val = &tmp; | ||
| 79 | } else if (grp == 6 && reg == 7) { | ||
| 80 | __asm__ __volatile__("%0 = cycles2;\n" : "=d"(tmp)); | ||
| 81 | val = &tmp; | ||
| 82 | } | ||
| 83 | |||
| 84 | *value = *val; | ||
| 85 | return true; | ||
| 86 | |||
| 87 | } | ||
| 88 | |||
| 89 | #define PseudoDbg_Assert_opcode 0xf0000000 | ||
| 90 | #define PseudoDbg_Assert_expected_bits 0 | ||
| 91 | #define PseudoDbg_Assert_expected_mask 0xffff | ||
| 92 | #define PseudoDbg_Assert_regtest_bits 16 | ||
| 93 | #define PseudoDbg_Assert_regtest_mask 0x7 | ||
| 94 | #define PseudoDbg_Assert_grp_bits 19 | ||
| 95 | #define PseudoDbg_Assert_grp_mask 0x7 | ||
| 96 | #define PseudoDbg_Assert_dbgop_bits 22 | ||
| 97 | #define PseudoDbg_Assert_dbgop_mask 0x3 | ||
| 98 | #define PseudoDbg_Assert_dontcare_bits 24 | ||
| 99 | #define PseudoDbg_Assert_dontcare_mask 0x7 | ||
| 100 | #define PseudoDbg_Assert_code_bits 27 | ||
| 101 | #define PseudoDbg_Assert_code_mask 0x1f | ||
| 102 | |||
| 103 | /* | ||
| 104 | * DBGA - debug assert | ||
| 105 | */ | ||
| 106 | bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) | ||
| 107 | { | ||
| 108 | int expected = ((opcode >> PseudoDbg_Assert_expected_bits) & PseudoDbg_Assert_expected_mask); | ||
| 109 | int dbgop = ((opcode >> (PseudoDbg_Assert_dbgop_bits)) & PseudoDbg_Assert_dbgop_mask); | ||
| 110 | int grp = ((opcode >> (PseudoDbg_Assert_grp_bits)) & PseudoDbg_Assert_grp_mask); | ||
| 111 | int regtest = ((opcode >> (PseudoDbg_Assert_regtest_bits)) & PseudoDbg_Assert_regtest_mask); | ||
| 112 | long value; | ||
| 113 | |||
| 114 | if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode) | ||
| 115 | return false; | ||
| 116 | |||
| 117 | if (!fix_up_reg(fp, &value, grp, regtest)) | ||
| 118 | return false; | ||
| 119 | |||
| 120 | if (dbgop == 0 || dbgop == 2) { | ||
| 121 | /* DBGA ( regs_lo , uimm16 ) */ | ||
| 122 | /* DBGAL ( regs , uimm16 ) */ | ||
| 123 | if (expected != (value & 0xFFFF)) { | ||
| 124 | pr_notice("DBGA (%s.L,0x%x) failure, got 0x%x\n", | ||
| 125 | get_allreg_name(grp, regtest), | ||
| 126 | expected, (unsigned int)(value & 0xFFFF)); | ||
| 127 | return false; | ||
| 128 | } | ||
| 129 | |||
| 130 | } else if (dbgop == 1 || dbgop == 3) { | ||
| 131 | /* DBGA ( regs_hi , uimm16 ) */ | ||
| 132 | /* DBGAH ( regs , uimm16 ) */ | ||
| 133 | if (expected != ((value >> 16) & 0xFFFF)) { | ||
| 134 | pr_notice("DBGA (%s.H,0x%x) failure, got 0x%x\n", | ||
| 135 | get_allreg_name(grp, regtest), | ||
| 136 | expected, (unsigned int)((value >> 16) & 0xFFFF)); | ||
| 137 | return false; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | fp->pc += 4; | ||
| 142 | return true; | ||
| 143 | } | ||
| 144 | |||
| 145 | #define PseudoDbg_opcode 0xf8000000 | ||
| 146 | #define PseudoDbg_reg_bits 0 | ||
| 147 | #define PseudoDbg_reg_mask 0x7 | ||
| 148 | #define PseudoDbg_grp_bits 3 | ||
| 149 | #define PseudoDbg_grp_mask 0x7 | ||
| 150 | #define PseudoDbg_fn_bits 6 | ||
| 151 | #define PseudoDbg_fn_mask 0x3 | ||
| 152 | #define PseudoDbg_code_bits 8 | ||
| 153 | #define PseudoDbg_code_mask 0xff | ||
| 154 | |||
| 155 | /* | ||
| 156 | * DBG - debug (dump a register value out) | ||
| 157 | */ | ||
| 158 | bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode) | ||
| 159 | { | ||
| 160 | int grp, fn, reg; | ||
| 161 | long value, value1; | ||
| 162 | |||
| 163 | if ((opcode & 0xFF000000) != PseudoDbg_opcode) | ||
| 164 | return false; | ||
| 165 | |||
| 166 | opcode >>= 16; | ||
| 167 | grp = ((opcode >> PseudoDbg_grp_bits) & PseudoDbg_reg_mask); | ||
| 168 | fn = ((opcode >> PseudoDbg_fn_bits) & PseudoDbg_fn_mask); | ||
| 169 | reg = ((opcode >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask); | ||
| 170 | |||
| 171 | if (fn == 3 && (reg == 0 || reg == 1)) { | ||
| 172 | if (!fix_up_reg(fp, &value, 4, 2 * reg)) | ||
| 173 | return false; | ||
| 174 | if (!fix_up_reg(fp, &value1, 4, 2 * reg + 1)) | ||
| 175 | return false; | ||
| 176 | |||
| 177 | pr_notice("DBG A%i = %02lx%08lx\n", reg, value & 0xFF, value1); | ||
| 178 | fp->pc += 2; | ||
| 179 | return true; | ||
| 180 | |||
| 181 | } else if (fn == 0) { | ||
| 182 | if (!fix_up_reg(fp, &value, grp, reg)) | ||
| 183 | return false; | ||
| 184 | |||
| 185 | pr_notice("DBG %s = %08lx\n", get_allreg_name(grp, reg), value); | ||
| 186 | fp->pc += 2; | ||
| 187 | return true; | ||
| 188 | } | ||
| 189 | |||
| 190 | return false; | ||
| 191 | } | ||
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 8e2efceb364b..d37a397f43f5 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2004-2009 Analog Devices Inc. | 2 | * Copyright 2004-2010 Analog Devices Inc. |
| 3 | * | 3 | * |
| 4 | * Licensed under the GPL-2 or later. | 4 | * Licensed under the GPL-2 or later. |
| 5 | */ | 5 | */ |
| @@ -925,7 +925,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 925 | else if (_bfin_swrst & RESET_SOFTWARE) | 925 | else if (_bfin_swrst & RESET_SOFTWARE) |
| 926 | printk(KERN_NOTICE "Reset caused by Software reset\n"); | 926 | printk(KERN_NOTICE "Reset caused by Software reset\n"); |
| 927 | 927 | ||
| 928 | printk(KERN_INFO "Blackfin support (C) 2004-2009 Analog Devices, Inc.\n"); | 928 | printk(KERN_INFO "Blackfin support (C) 2004-2010 Analog Devices, Inc.\n"); |
| 929 | if (bfin_compiled_revid() == 0xffff) | 929 | if (bfin_compiled_revid() == 0xffff) |
| 930 | printk(KERN_INFO "Compiled for ADSP-%s Rev any, running on 0.%d\n", CPU, bfin_revid()); | 930 | printk(KERN_INFO "Compiled for ADSP-%s Rev any, running on 0.%d\n", CPU, bfin_revid()); |
| 931 | else if (bfin_compiled_revid() == -1) | 931 | else if (bfin_compiled_revid() == -1) |
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c index 2e7f8e10bf87..bdc1e2f0da32 100644 --- a/arch/blackfin/kernel/sys_bfin.c +++ b/arch/blackfin/kernel/sys_bfin.c | |||
| @@ -47,3 +47,26 @@ unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, | |||
| 47 | } | 47 | } |
| 48 | EXPORT_SYMBOL(get_fb_unmapped_area); | 48 | EXPORT_SYMBOL(get_fb_unmapped_area); |
| 49 | #endif | 49 | #endif |
| 50 | |||
| 51 | /* Needed for legacy userspace atomic emulation */ | ||
| 52 | static DEFINE_SPINLOCK(bfin_spinlock_lock); | ||
| 53 | |||
| 54 | #ifdef CONFIG_SYS_BFIN_SPINLOCK_L1 | ||
| 55 | __attribute__((l1_text)) | ||
| 56 | #endif | ||
| 57 | asmlinkage int sys_bfin_spinlock(int *p) | ||
| 58 | { | ||
| 59 | int ret, tmp = 0; | ||
| 60 | |||
| 61 | spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */ | ||
| 62 | ret = get_user(tmp, p); | ||
| 63 | if (likely(ret == 0)) { | ||
| 64 | if (unlikely(tmp)) | ||
| 65 | ret = 1; | ||
| 66 | else | ||
| 67 | put_user(1, p); | ||
| 68 | } | ||
| 69 | spin_unlock(&bfin_spinlock_lock); | ||
| 70 | |||
| 71 | return ret; | ||
| 72 | } | ||
diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c new file mode 100644 index 000000000000..59fcdf6b0138 --- /dev/null +++ b/arch/blackfin/kernel/trace.c | |||
| @@ -0,0 +1,981 @@ | |||
| 1 | /* provide some functions which dump the trace buffer, in a nice way for people | ||
| 2 | * to read it, and understand what is going on | ||
| 3 | * | ||
| 4 | * Copyright 2004-2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/hardirq.h> | ||
| 11 | #include <linux/thread_info.h> | ||
| 12 | #include <linux/mm.h> | ||
| 13 | #include <linux/uaccess.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/kallsyms.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/fs.h> | ||
| 18 | #include <asm/dma.h> | ||
| 19 | #include <asm/trace.h> | ||
| 20 | #include <asm/fixed_code.h> | ||
| 21 | #include <asm/traps.h> | ||
| 22 | #include <asm/irq_handler.h> | ||
| 23 | |||
| 24 | void decode_address(char *buf, unsigned long address) | ||
| 25 | { | ||
| 26 | struct task_struct *p; | ||
| 27 | struct mm_struct *mm; | ||
| 28 | unsigned long flags, offset; | ||
| 29 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | ||
| 30 | struct rb_node *n; | ||
| 31 | |||
| 32 | #ifdef CONFIG_KALLSYMS | ||
| 33 | unsigned long symsize; | ||
| 34 | const char *symname; | ||
| 35 | char *modname; | ||
| 36 | char *delim = ":"; | ||
| 37 | char namebuf[128]; | ||
| 38 | #endif | ||
| 39 | |||
| 40 | buf += sprintf(buf, "<0x%08lx> ", address); | ||
| 41 | |||
| 42 | #ifdef CONFIG_KALLSYMS | ||
| 43 | /* look up the address and see if we are in kernel space */ | ||
| 44 | symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf); | ||
| 45 | |||
| 46 | if (symname) { | ||
| 47 | /* yeah! kernel space! */ | ||
| 48 | if (!modname) | ||
| 49 | modname = delim = ""; | ||
| 50 | sprintf(buf, "{ %s%s%s%s + 0x%lx }", | ||
| 51 | delim, modname, delim, symname, | ||
| 52 | (unsigned long)offset); | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | #endif | ||
| 56 | |||
| 57 | if (address >= FIXED_CODE_START && address < FIXED_CODE_END) { | ||
| 58 | /* Problem in fixed code section? */ | ||
| 59 | strcat(buf, "/* Maybe fixed code section */"); | ||
| 60 | return; | ||
| 61 | |||
| 62 | } else if (address < CONFIG_BOOT_LOAD) { | ||
| 63 | /* Problem somewhere before the kernel start address */ | ||
| 64 | strcat(buf, "/* Maybe null pointer? */"); | ||
| 65 | return; | ||
| 66 | |||
| 67 | } else if (address >= COREMMR_BASE) { | ||
| 68 | strcat(buf, "/* core mmrs */"); | ||
| 69 | return; | ||
| 70 | |||
| 71 | } else if (address >= SYSMMR_BASE) { | ||
| 72 | strcat(buf, "/* system mmrs */"); | ||
| 73 | return; | ||
| 74 | |||
| 75 | } else if (address >= L1_ROM_START && address < L1_ROM_START + L1_ROM_LENGTH) { | ||
| 76 | strcat(buf, "/* on-chip L1 ROM */"); | ||
| 77 | return; | ||
| 78 | |||
| 79 | } else if (address >= L1_SCRATCH_START && address < L1_SCRATCH_START + L1_SCRATCH_LENGTH) { | ||
| 80 | strcat(buf, "/* on-chip scratchpad */"); | ||
| 81 | return; | ||
| 82 | |||
| 83 | } else if (address >= physical_mem_end && address < ASYNC_BANK0_BASE) { | ||
| 84 | strcat(buf, "/* unconnected memory */"); | ||
| 85 | return; | ||
| 86 | |||
| 87 | } else if (address >= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE && address < BOOT_ROM_START) { | ||
| 88 | strcat(buf, "/* reserved memory */"); | ||
| 89 | return; | ||
| 90 | |||
| 91 | } else if (address >= L1_DATA_A_START && address < L1_DATA_A_START + L1_DATA_A_LENGTH) { | ||
| 92 | strcat(buf, "/* on-chip Data Bank A */"); | ||
| 93 | return; | ||
| 94 | |||
| 95 | } else if (address >= L1_DATA_B_START && address < L1_DATA_B_START + L1_DATA_B_LENGTH) { | ||
| 96 | strcat(buf, "/* on-chip Data Bank B */"); | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Don't walk any of the vmas if we are oopsing, it has been known | ||
| 102 | * to cause problems - corrupt vmas (kernel crashes) cause double faults | ||
| 103 | */ | ||
| 104 | if (oops_in_progress) { | ||
| 105 | strcat(buf, "/* kernel dynamic memory (maybe user-space) */"); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* looks like we're off in user-land, so let's walk all the | ||
| 110 | * mappings of all our processes and see if we can't be a whee | ||
| 111 | * bit more specific | ||
| 112 | */ | ||
| 113 | write_lock_irqsave(&tasklist_lock, flags); | ||
| 114 | for_each_process(p) { | ||
| 115 | mm = (in_atomic ? p->mm : get_task_mm(p)); | ||
| 116 | if (!mm) | ||
| 117 | continue; | ||
| 118 | |||
| 119 | if (!down_read_trylock(&mm->mmap_sem)) { | ||
| 120 | if (!in_atomic) | ||
| 121 | mmput(mm); | ||
| 122 | continue; | ||
| 123 | } | ||
| 124 | |||
| 125 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { | ||
| 126 | struct vm_area_struct *vma; | ||
| 127 | |||
| 128 | vma = rb_entry(n, struct vm_area_struct, vm_rb); | ||
| 129 | |||
| 130 | if (address >= vma->vm_start && address < vma->vm_end) { | ||
| 131 | char _tmpbuf[256]; | ||
| 132 | char *name = p->comm; | ||
| 133 | struct file *file = vma->vm_file; | ||
| 134 | |||
| 135 | if (file) { | ||
| 136 | char *d_name = d_path(&file->f_path, _tmpbuf, | ||
| 137 | sizeof(_tmpbuf)); | ||
| 138 | if (!IS_ERR(d_name)) | ||
| 139 | name = d_name; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* FLAT does not have its text aligned to the start of | ||
| 143 | * the map while FDPIC ELF does ... | ||
| 144 | */ | ||
| 145 | |||
| 146 | /* before we can check flat/fdpic, we need to | ||
| 147 | * make sure current is valid | ||
| 148 | */ | ||
| 149 | if ((unsigned long)current >= FIXED_CODE_START && | ||
| 150 | !((unsigned long)current & 0x3)) { | ||
| 151 | if (current->mm && | ||
| 152 | (address > current->mm->start_code) && | ||
| 153 | (address < current->mm->end_code)) | ||
| 154 | offset = address - current->mm->start_code; | ||
| 155 | else | ||
| 156 | offset = (address - vma->vm_start) + | ||
| 157 | (vma->vm_pgoff << PAGE_SHIFT); | ||
| 158 | |||
| 159 | sprintf(buf, "[ %s + 0x%lx ]", name, offset); | ||
| 160 | } else | ||
| 161 | sprintf(buf, "[ %s vma:0x%lx-0x%lx]", | ||
| 162 | name, vma->vm_start, vma->vm_end); | ||
| 163 | |||
| 164 | up_read(&mm->mmap_sem); | ||
| 165 | if (!in_atomic) | ||
| 166 | mmput(mm); | ||
| 167 | |||
| 168 | if (buf[0] == '\0') | ||
| 169 | sprintf(buf, "[ %s ] dynamic memory", name); | ||
| 170 | |||
| 171 | goto done; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | up_read(&mm->mmap_sem); | ||
| 176 | if (!in_atomic) | ||
| 177 | mmput(mm); | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * we were unable to find this address anywhere, | ||
| 182 | * or some MMs were skipped because they were in use. | ||
| 183 | */ | ||
| 184 | sprintf(buf, "/* kernel dynamic memory */"); | ||
| 185 | |||
| 186 | done: | ||
| 187 | write_unlock_irqrestore(&tasklist_lock, flags); | ||
| 188 | } | ||
| 189 | |||
| 190 | #define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1) | ||
| 191 | |||
| 192 | /* | ||
| 193 | * Similar to get_user, do some address checking, then dereference | ||
| 194 | * Return true on success, false on bad address | ||
| 195 | */ | ||
| 196 | bool get_mem16(unsigned short *val, unsigned short *address) | ||
| 197 | { | ||
| 198 | unsigned long addr = (unsigned long)address; | ||
| 199 | |||
| 200 | /* Check for odd addresses */ | ||
| 201 | if (addr & 0x1) | ||
| 202 | return false; | ||
| 203 | |||
| 204 | switch (bfin_mem_access_type(addr, 2)) { | ||
| 205 | case BFIN_MEM_ACCESS_CORE: | ||
| 206 | case BFIN_MEM_ACCESS_CORE_ONLY: | ||
| 207 | *val = *address; | ||
| 208 | return true; | ||
| 209 | case BFIN_MEM_ACCESS_DMA: | ||
| 210 | dma_memcpy(val, address, 2); | ||
| 211 | return true; | ||
| 212 | case BFIN_MEM_ACCESS_ITEST: | ||
| 213 | isram_memcpy(val, address, 2); | ||
| 214 | return true; | ||
| 215 | default: /* invalid access */ | ||
| 216 | return false; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | bool get_instruction(unsigned int *val, unsigned short *address) | ||
| 221 | { | ||
| 222 | unsigned long addr = (unsigned long)address; | ||
| 223 | unsigned short opcode0, opcode1; | ||
| 224 | |||
| 225 | /* Check for odd addresses */ | ||
| 226 | if (addr & 0x1) | ||
| 227 | return false; | ||
| 228 | |||
| 229 | /* MMR region will never have instructions */ | ||
| 230 | if (addr >= SYSMMR_BASE) | ||
| 231 | return false; | ||
| 232 | |||
| 233 | /* Scratchpad will never have instructions */ | ||
| 234 | if (addr >= L1_SCRATCH_START && addr < L1_SCRATCH_START + L1_SCRATCH_LENGTH) | ||
| 235 | return false; | ||
| 236 | |||
| 237 | /* Data banks will never have instructions */ | ||
| 238 | if (addr >= BOOT_ROM_START + BOOT_ROM_LENGTH && addr < L1_CODE_START) | ||
| 239 | return false; | ||
| 240 | |||
| 241 | if (!get_mem16(&opcode0, address)) | ||
| 242 | return false; | ||
| 243 | |||
| 244 | /* was this a 32-bit instruction? If so, get the next 16 bits */ | ||
| 245 | if ((opcode0 & 0xc000) == 0xc000) { | ||
| 246 | if (!get_mem16(&opcode1, address + 1)) | ||
| 247 | return false; | ||
| 248 | *val = (opcode0 << 16) + opcode1; | ||
| 249 | } else | ||
| 250 | *val = opcode0; | ||
| 251 | |||
| 252 | return true; | ||
| 253 | } | ||
| 254 | |||
| 255 | #if defined(CONFIG_DEBUG_BFIN_HWTRACE_ON) | ||
| 256 | /* | ||
| 257 | * decode the instruction if we are printing out the trace, as it | ||
| 258 | * makes things easier to follow, without running it through objdump | ||
| 259 | * Decode the change of flow, and the common load/store instructions | ||
| 260 | * which are the main cause for faults, and discontinuities in the trace | ||
| 261 | * buffer. | ||
| 262 | */ | ||
| 263 | |||
| 264 | #define ProgCtrl_opcode 0x0000 | ||
| 265 | #define ProgCtrl_poprnd_bits 0 | ||
| 266 | #define ProgCtrl_poprnd_mask 0xf | ||
| 267 | #define ProgCtrl_prgfunc_bits 4 | ||
| 268 | #define ProgCtrl_prgfunc_mask 0xf | ||
| 269 | #define ProgCtrl_code_bits 8 | ||
| 270 | #define ProgCtrl_code_mask 0xff | ||
| 271 | |||
| 272 | static void decode_ProgCtrl_0(unsigned int opcode) | ||
| 273 | { | ||
| 274 | int poprnd = ((opcode >> ProgCtrl_poprnd_bits) & ProgCtrl_poprnd_mask); | ||
| 275 | int prgfunc = ((opcode >> ProgCtrl_prgfunc_bits) & ProgCtrl_prgfunc_mask); | ||
| 276 | |||
| 277 | if (prgfunc == 0 && poprnd == 0) | ||
| 278 | pr_cont("NOP"); | ||
| 279 | else if (prgfunc == 1 && poprnd == 0) | ||
| 280 | pr_cont("RTS"); | ||
| 281 | else if (prgfunc == 1 && poprnd == 1) | ||
| 282 | pr_cont("RTI"); | ||
| 283 | else if (prgfunc == 1 && poprnd == 2) | ||
| 284 | pr_cont("RTX"); | ||
| 285 | else if (prgfunc == 1 && poprnd == 3) | ||
| 286 | pr_cont("RTN"); | ||
| 287 | else if (prgfunc == 1 && poprnd == 4) | ||
| 288 | pr_cont("RTE"); | ||
| 289 | else if (prgfunc == 2 && poprnd == 0) | ||
| 290 | pr_cont("IDLE"); | ||
| 291 | else if (prgfunc == 2 && poprnd == 3) | ||
| 292 | pr_cont("CSYNC"); | ||
| 293 | else if (prgfunc == 2 && poprnd == 4) | ||
| 294 | pr_cont("SSYNC"); | ||
| 295 | else if (prgfunc == 2 && poprnd == 5) | ||
| 296 | pr_cont("EMUEXCPT"); | ||
| 297 | else if (prgfunc == 3) | ||
| 298 | pr_cont("CLI R%i", poprnd); | ||
| 299 | else if (prgfunc == 4) | ||
| 300 | pr_cont("STI R%i", poprnd); | ||
| 301 | else if (prgfunc == 5) | ||
| 302 | pr_cont("JUMP (P%i)", poprnd); | ||
| 303 | else if (prgfunc == 6) | ||
| 304 | pr_cont("CALL (P%i)", poprnd); | ||
| 305 | else if (prgfunc == 7) | ||
| 306 | pr_cont("CALL (PC + P%i)", poprnd); | ||
| 307 | else if (prgfunc == 8) | ||
| 308 | pr_cont("JUMP (PC + P%i", poprnd); | ||
| 309 | else if (prgfunc == 9) | ||
| 310 | pr_cont("RAISE %i", poprnd); | ||
| 311 | else if (prgfunc == 10) | ||
| 312 | pr_cont("EXCPT %i", poprnd); | ||
| 313 | else | ||
| 314 | pr_cont("0x%04x", opcode); | ||
| 315 | |||
| 316 | } | ||
| 317 | |||
| 318 | #define BRCC_opcode 0x1000 | ||
| 319 | #define BRCC_offset_bits 0 | ||
| 320 | #define BRCC_offset_mask 0x3ff | ||
| 321 | #define BRCC_B_bits 10 | ||
| 322 | #define BRCC_B_mask 0x1 | ||
| 323 | #define BRCC_T_bits 11 | ||
| 324 | #define BRCC_T_mask 0x1 | ||
| 325 | #define BRCC_code_bits 12 | ||
| 326 | #define BRCC_code_mask 0xf | ||
| 327 | |||
| 328 | static void decode_BRCC_0(unsigned int opcode) | ||
| 329 | { | ||
| 330 | int B = ((opcode >> BRCC_B_bits) & BRCC_B_mask); | ||
| 331 | int T = ((opcode >> BRCC_T_bits) & BRCC_T_mask); | ||
| 332 | |||
| 333 | pr_cont("IF %sCC JUMP pcrel %s", T ? "" : "!", B ? "(BP)" : ""); | ||
| 334 | } | ||
| 335 | |||
| 336 | #define CALLa_opcode 0xe2000000 | ||
| 337 | #define CALLa_addr_bits 0 | ||
| 338 | #define CALLa_addr_mask 0xffffff | ||
| 339 | #define CALLa_S_bits 24 | ||
| 340 | #define CALLa_S_mask 0x1 | ||
| 341 | #define CALLa_code_bits 25 | ||
| 342 | #define CALLa_code_mask 0x7f | ||
| 343 | |||
| 344 | static void decode_CALLa_0(unsigned int opcode) | ||
| 345 | { | ||
| 346 | int S = ((opcode >> (CALLa_S_bits - 16)) & CALLa_S_mask); | ||
| 347 | |||
| 348 | if (S) | ||
| 349 | pr_cont("CALL pcrel"); | ||
| 350 | else | ||
| 351 | pr_cont("JUMP.L"); | ||
| 352 | } | ||
| 353 | |||
| 354 | #define LoopSetup_opcode 0xe0800000 | ||
| 355 | #define LoopSetup_eoffset_bits 0 | ||
| 356 | #define LoopSetup_eoffset_mask 0x3ff | ||
| 357 | #define LoopSetup_dontcare_bits 10 | ||
| 358 | #define LoopSetup_dontcare_mask 0x3 | ||
| 359 | #define LoopSetup_reg_bits 12 | ||
| 360 | #define LoopSetup_reg_mask 0xf | ||
| 361 | #define LoopSetup_soffset_bits 16 | ||
| 362 | #define LoopSetup_soffset_mask 0xf | ||
| 363 | #define LoopSetup_c_bits 20 | ||
| 364 | #define LoopSetup_c_mask 0x1 | ||
| 365 | #define LoopSetup_rop_bits 21 | ||
| 366 | #define LoopSetup_rop_mask 0x3 | ||
| 367 | #define LoopSetup_code_bits 23 | ||
| 368 | #define LoopSetup_code_mask 0x1ff | ||
| 369 | |||
| 370 | static void decode_LoopSetup_0(unsigned int opcode) | ||
| 371 | { | ||
| 372 | int c = ((opcode >> LoopSetup_c_bits) & LoopSetup_c_mask); | ||
| 373 | int reg = ((opcode >> LoopSetup_reg_bits) & LoopSetup_reg_mask); | ||
| 374 | int rop = ((opcode >> LoopSetup_rop_bits) & LoopSetup_rop_mask); | ||
| 375 | |||
| 376 | pr_cont("LSETUP <> LC%i", c); | ||
| 377 | if ((rop & 1) == 1) | ||
| 378 | pr_cont("= P%i", reg); | ||
| 379 | if ((rop & 2) == 2) | ||
| 380 | pr_cont(" >> 0x1"); | ||
| 381 | } | ||
| 382 | |||
| 383 | #define DspLDST_opcode 0x9c00 | ||
| 384 | #define DspLDST_reg_bits 0 | ||
| 385 | #define DspLDST_reg_mask 0x7 | ||
| 386 | #define DspLDST_i_bits 3 | ||
| 387 | #define DspLDST_i_mask 0x3 | ||
| 388 | #define DspLDST_m_bits 5 | ||
| 389 | #define DspLDST_m_mask 0x3 | ||
| 390 | #define DspLDST_aop_bits 7 | ||
| 391 | #define DspLDST_aop_mask 0x3 | ||
| 392 | #define DspLDST_W_bits 9 | ||
| 393 | #define DspLDST_W_mask 0x1 | ||
| 394 | #define DspLDST_code_bits 10 | ||
| 395 | #define DspLDST_code_mask 0x3f | ||
| 396 | |||
| 397 | static void decode_dspLDST_0(unsigned int opcode) | ||
| 398 | { | ||
| 399 | int i = ((opcode >> DspLDST_i_bits) & DspLDST_i_mask); | ||
| 400 | int m = ((opcode >> DspLDST_m_bits) & DspLDST_m_mask); | ||
| 401 | int W = ((opcode >> DspLDST_W_bits) & DspLDST_W_mask); | ||
| 402 | int aop = ((opcode >> DspLDST_aop_bits) & DspLDST_aop_mask); | ||
| 403 | int reg = ((opcode >> DspLDST_reg_bits) & DspLDST_reg_mask); | ||
| 404 | |||
| 405 | if (W == 0) { | ||
| 406 | pr_cont("R%i", reg); | ||
| 407 | switch (m) { | ||
| 408 | case 0: | ||
| 409 | pr_cont(" = "); | ||
| 410 | break; | ||
| 411 | case 1: | ||
| 412 | pr_cont(".L = "); | ||
| 413 | break; | ||
| 414 | case 2: | ||
| 415 | pr_cont(".W = "); | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | pr_cont("[ I%i", i); | ||
| 421 | |||
| 422 | switch (aop) { | ||
| 423 | case 0: | ||
| 424 | pr_cont("++ ]"); | ||
| 425 | break; | ||
| 426 | case 1: | ||
| 427 | pr_cont("-- ]"); | ||
| 428 | break; | ||
| 429 | } | ||
| 430 | |||
| 431 | if (W == 1) { | ||
| 432 | pr_cont(" = R%i", reg); | ||
| 433 | switch (m) { | ||
| 434 | case 1: | ||
| 435 | pr_cont(".L = "); | ||
| 436 | break; | ||
| 437 | case 2: | ||
| 438 | pr_cont(".W = "); | ||
| 439 | break; | ||
| 440 | } | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | #define LDST_opcode 0x9000 | ||
| 445 | #define LDST_reg_bits 0 | ||
| 446 | #define LDST_reg_mask 0x7 | ||
| 447 | #define LDST_ptr_bits 3 | ||
| 448 | #define LDST_ptr_mask 0x7 | ||
| 449 | #define LDST_Z_bits 6 | ||
| 450 | #define LDST_Z_mask 0x1 | ||
| 451 | #define LDST_aop_bits 7 | ||
| 452 | #define LDST_aop_mask 0x3 | ||
| 453 | #define LDST_W_bits 9 | ||
| 454 | #define LDST_W_mask 0x1 | ||
| 455 | #define LDST_sz_bits 10 | ||
| 456 | #define LDST_sz_mask 0x3 | ||
| 457 | #define LDST_code_bits 12 | ||
| 458 | #define LDST_code_mask 0xf | ||
| 459 | |||
| 460 | static void decode_LDST_0(unsigned int opcode) | ||
| 461 | { | ||
| 462 | int Z = ((opcode >> LDST_Z_bits) & LDST_Z_mask); | ||
| 463 | int W = ((opcode >> LDST_W_bits) & LDST_W_mask); | ||
| 464 | int sz = ((opcode >> LDST_sz_bits) & LDST_sz_mask); | ||
| 465 | int aop = ((opcode >> LDST_aop_bits) & LDST_aop_mask); | ||
| 466 | int reg = ((opcode >> LDST_reg_bits) & LDST_reg_mask); | ||
| 467 | int ptr = ((opcode >> LDST_ptr_bits) & LDST_ptr_mask); | ||
| 468 | |||
| 469 | if (W == 0) | ||
| 470 | pr_cont("%s%i = ", (sz == 0 && Z == 1) ? "P" : "R", reg); | ||
| 471 | |||
| 472 | switch (sz) { | ||
| 473 | case 1: | ||
| 474 | pr_cont("W"); | ||
| 475 | break; | ||
| 476 | case 2: | ||
| 477 | pr_cont("B"); | ||
| 478 | break; | ||
| 479 | } | ||
| 480 | |||
| 481 | pr_cont("[P%i", ptr); | ||
| 482 | |||
| 483 | switch (aop) { | ||
| 484 | case 0: | ||
| 485 | pr_cont("++"); | ||
| 486 | break; | ||
| 487 | case 1: | ||
| 488 | pr_cont("--"); | ||
| 489 | break; | ||
| 490 | } | ||
| 491 | pr_cont("]"); | ||
| 492 | |||
| 493 | if (W == 1) | ||
| 494 | pr_cont(" = %s%i ", (sz == 0 && Z == 1) ? "P" : "R", reg); | ||
| 495 | |||
| 496 | if (sz) { | ||
| 497 | if (Z) | ||
| 498 | pr_cont(" (X)"); | ||
| 499 | else | ||
| 500 | pr_cont(" (Z)"); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | |||
| 504 | #define LDSTii_opcode 0xa000 | ||
| 505 | #define LDSTii_reg_bit 0 | ||
| 506 | #define LDSTii_reg_mask 0x7 | ||
| 507 | #define LDSTii_ptr_bit 3 | ||
| 508 | #define LDSTii_ptr_mask 0x7 | ||
| 509 | #define LDSTii_offset_bit 6 | ||
| 510 | #define LDSTii_offset_mask 0xf | ||
| 511 | #define LDSTii_op_bit 10 | ||
| 512 | #define LDSTii_op_mask 0x3 | ||
| 513 | #define LDSTii_W_bit 12 | ||
| 514 | #define LDSTii_W_mask 0x1 | ||
| 515 | #define LDSTii_code_bit 13 | ||
| 516 | #define LDSTii_code_mask 0x7 | ||
| 517 | |||
| 518 | static void decode_LDSTii_0(unsigned int opcode) | ||
| 519 | { | ||
| 520 | int reg = ((opcode >> LDSTii_reg_bit) & LDSTii_reg_mask); | ||
| 521 | int ptr = ((opcode >> LDSTii_ptr_bit) & LDSTii_ptr_mask); | ||
| 522 | int offset = ((opcode >> LDSTii_offset_bit) & LDSTii_offset_mask); | ||
| 523 | int op = ((opcode >> LDSTii_op_bit) & LDSTii_op_mask); | ||
| 524 | int W = ((opcode >> LDSTii_W_bit) & LDSTii_W_mask); | ||
| 525 | |||
| 526 | if (W == 0) { | ||
| 527 | pr_cont("%s%i = %s[P%i + %i]", op == 3 ? "R" : "P", reg, | ||
| 528 | op == 1 || op == 2 ? "" : "W", ptr, offset); | ||
| 529 | if (op == 2) | ||
| 530 | pr_cont("(Z)"); | ||
| 531 | if (op == 3) | ||
| 532 | pr_cont("(X)"); | ||
| 533 | } else { | ||
| 534 | pr_cont("%s[P%i + %i] = %s%i", op == 0 ? "" : "W", ptr, | ||
| 535 | offset, op == 3 ? "P" : "R", reg); | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | #define LDSTidxI_opcode 0xe4000000 | ||
| 540 | #define LDSTidxI_offset_bits 0 | ||
| 541 | #define LDSTidxI_offset_mask 0xffff | ||
| 542 | #define LDSTidxI_reg_bits 16 | ||
| 543 | #define LDSTidxI_reg_mask 0x7 | ||
| 544 | #define LDSTidxI_ptr_bits 19 | ||
| 545 | #define LDSTidxI_ptr_mask 0x7 | ||
| 546 | #define LDSTidxI_sz_bits 22 | ||
| 547 | #define LDSTidxI_sz_mask 0x3 | ||
| 548 | #define LDSTidxI_Z_bits 24 | ||
| 549 | #define LDSTidxI_Z_mask 0x1 | ||
| 550 | #define LDSTidxI_W_bits 25 | ||
| 551 | #define LDSTidxI_W_mask 0x1 | ||
| 552 | #define LDSTidxI_code_bits 26 | ||
| 553 | #define LDSTidxI_code_mask 0x3f | ||
| 554 | |||
| 555 | static void decode_LDSTidxI_0(unsigned int opcode) | ||
| 556 | { | ||
| 557 | int Z = ((opcode >> LDSTidxI_Z_bits) & LDSTidxI_Z_mask); | ||
| 558 | int W = ((opcode >> LDSTidxI_W_bits) & LDSTidxI_W_mask); | ||
| 559 | int sz = ((opcode >> LDSTidxI_sz_bits) & LDSTidxI_sz_mask); | ||
| 560 | int reg = ((opcode >> LDSTidxI_reg_bits) & LDSTidxI_reg_mask); | ||
| 561 | int ptr = ((opcode >> LDSTidxI_ptr_bits) & LDSTidxI_ptr_mask); | ||
| 562 | int offset = ((opcode >> LDSTidxI_offset_bits) & LDSTidxI_offset_mask); | ||
| 563 | |||
| 564 | if (W == 0) | ||
| 565 | pr_cont("%s%i = ", sz == 0 && Z == 1 ? "P" : "R", reg); | ||
| 566 | |||
| 567 | if (sz == 1) | ||
| 568 | pr_cont("W"); | ||
| 569 | if (sz == 2) | ||
| 570 | pr_cont("B"); | ||
| 571 | |||
| 572 | pr_cont("[P%i + %s0x%x]", ptr, offset & 0x20 ? "-" : "", | ||
| 573 | (offset & 0x1f) << 2); | ||
| 574 | |||
| 575 | if (W == 0 && sz != 0) { | ||
| 576 | if (Z) | ||
| 577 | pr_cont("(X)"); | ||
| 578 | else | ||
| 579 | pr_cont("(Z)"); | ||
| 580 | } | ||
| 581 | |||
| 582 | if (W == 1) | ||
| 583 | pr_cont("= %s%i", (sz == 0 && Z == 1) ? "P" : "R", reg); | ||
| 584 | |||
| 585 | } | ||
| 586 | |||
| 587 | static void decode_opcode(unsigned int opcode) | ||
| 588 | { | ||
| 589 | #ifdef CONFIG_BUG | ||
| 590 | if (opcode == BFIN_BUG_OPCODE) | ||
| 591 | pr_cont("BUG"); | ||
| 592 | else | ||
| 593 | #endif | ||
| 594 | if ((opcode & 0xffffff00) == ProgCtrl_opcode) | ||
| 595 | decode_ProgCtrl_0(opcode); | ||
| 596 | else if ((opcode & 0xfffff000) == BRCC_opcode) | ||
| 597 | decode_BRCC_0(opcode); | ||
| 598 | else if ((opcode & 0xfffff000) == 0x2000) | ||
| 599 | pr_cont("JUMP.S"); | ||
| 600 | else if ((opcode & 0xfe000000) == CALLa_opcode) | ||
| 601 | decode_CALLa_0(opcode); | ||
| 602 | else if ((opcode & 0xff8000C0) == LoopSetup_opcode) | ||
| 603 | decode_LoopSetup_0(opcode); | ||
| 604 | else if ((opcode & 0xfffffc00) == DspLDST_opcode) | ||
| 605 | decode_dspLDST_0(opcode); | ||
| 606 | else if ((opcode & 0xfffff000) == LDST_opcode) | ||
| 607 | decode_LDST_0(opcode); | ||
| 608 | else if ((opcode & 0xffffe000) == LDSTii_opcode) | ||
| 609 | decode_LDSTii_0(opcode); | ||
| 610 | else if ((opcode & 0xfc000000) == LDSTidxI_opcode) | ||
| 611 | decode_LDSTidxI_0(opcode); | ||
| 612 | else if (opcode & 0xffff0000) | ||
| 613 | pr_cont("0x%08x", opcode); | ||
| 614 | else | ||
| 615 | pr_cont("0x%04x", opcode); | ||
| 616 | } | ||
| 617 | |||
| 618 | #define BIT_MULTI_INS 0x08000000 | ||
| 619 | static void decode_instruction(unsigned short *address) | ||
| 620 | { | ||
| 621 | unsigned int opcode; | ||
| 622 | |||
| 623 | if (!get_instruction(&opcode, address)) | ||
| 624 | return; | ||
| 625 | |||
| 626 | decode_opcode(opcode); | ||
| 627 | |||
| 628 | /* If things are a 32-bit instruction, it has the possibility of being | ||
| 629 | * a multi-issue instruction (a 32-bit, and 2 16 bit instrucitions) | ||
| 630 | * This test collidates with the unlink instruction, so disallow that | ||
| 631 | */ | ||
| 632 | if ((opcode & 0xc0000000) == 0xc0000000 && | ||
| 633 | (opcode & BIT_MULTI_INS) && | ||
| 634 | (opcode & 0xe8000000) != 0xe8000000) { | ||
| 635 | pr_cont(" || "); | ||
| 636 | if (!get_instruction(&opcode, address + 2)) | ||
| 637 | return; | ||
| 638 | decode_opcode(opcode); | ||
| 639 | pr_cont(" || "); | ||
| 640 | if (!get_instruction(&opcode, address + 3)) | ||
| 641 | return; | ||
| 642 | decode_opcode(opcode); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | #endif | ||
| 646 | |||
| 647 | void dump_bfin_trace_buffer(void) | ||
| 648 | { | ||
| 649 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
| 650 | int tflags, i = 0, fault = 0; | ||
| 651 | char buf[150]; | ||
| 652 | unsigned short *addr; | ||
| 653 | unsigned int cpu = raw_smp_processor_id(); | ||
| 654 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
| 655 | int j, index; | ||
| 656 | #endif | ||
| 657 | |||
| 658 | trace_buffer_save(tflags); | ||
| 659 | |||
| 660 | pr_notice("Hardware Trace:\n"); | ||
| 661 | |||
| 662 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
| 663 | pr_notice("WARNING: Expanded trace turned on - can not trace exceptions\n"); | ||
| 664 | #endif | ||
| 665 | |||
| 666 | if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { | ||
| 667 | for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) { | ||
| 668 | addr = (unsigned short *)bfin_read_TBUF(); | ||
| 669 | decode_address(buf, (unsigned long)addr); | ||
| 670 | pr_notice("%4i Target : %s\n", i, buf); | ||
| 671 | /* Normally, the faulting instruction doesn't go into | ||
| 672 | * the trace buffer, (since it doesn't commit), so | ||
| 673 | * we print out the fault address here | ||
| 674 | */ | ||
| 675 | if (!fault && addr == ((unsigned short *)evt_ivhw)) { | ||
| 676 | addr = (unsigned short *)bfin_read_TBUF(); | ||
| 677 | decode_address(buf, (unsigned long)addr); | ||
| 678 | pr_notice(" FAULT : %s ", buf); | ||
| 679 | decode_instruction(addr); | ||
| 680 | pr_cont("\n"); | ||
| 681 | fault = 1; | ||
| 682 | continue; | ||
| 683 | } | ||
| 684 | if (!fault && addr == (unsigned short *)trap && | ||
| 685 | (cpu_pda[cpu].seqstat & SEQSTAT_EXCAUSE) > VEC_EXCPT15) { | ||
| 686 | decode_address(buf, cpu_pda[cpu].icplb_fault_addr); | ||
| 687 | pr_notice(" FAULT : %s ", buf); | ||
| 688 | decode_instruction((unsigned short *)cpu_pda[cpu].icplb_fault_addr); | ||
| 689 | pr_cont("\n"); | ||
| 690 | fault = 1; | ||
| 691 | } | ||
| 692 | addr = (unsigned short *)bfin_read_TBUF(); | ||
| 693 | decode_address(buf, (unsigned long)addr); | ||
| 694 | pr_notice(" Source : %s ", buf); | ||
| 695 | decode_instruction(addr); | ||
| 696 | pr_cont("\n"); | ||
| 697 | } | ||
| 698 | } | ||
| 699 | |||
| 700 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
| 701 | if (trace_buff_offset) | ||
| 702 | index = trace_buff_offset / 4; | ||
| 703 | else | ||
| 704 | index = EXPAND_LEN; | ||
| 705 | |||
| 706 | j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128; | ||
| 707 | while (j) { | ||
| 708 | decode_address(buf, software_trace_buff[index]); | ||
| 709 | pr_notice("%4i Target : %s\n", i, buf); | ||
| 710 | index -= 1; | ||
| 711 | if (index < 0) | ||
| 712 | index = EXPAND_LEN; | ||
| 713 | decode_address(buf, software_trace_buff[index]); | ||
| 714 | pr_notice(" Source : %s ", buf); | ||
| 715 | decode_instruction((unsigned short *)software_trace_buff[index]); | ||
| 716 | pr_cont("\n"); | ||
| 717 | index -= 1; | ||
| 718 | if (index < 0) | ||
| 719 | index = EXPAND_LEN; | ||
| 720 | j--; | ||
| 721 | i++; | ||
| 722 | } | ||
| 723 | #endif | ||
| 724 | |||
| 725 | trace_buffer_restore(tflags); | ||
| 726 | #endif | ||
| 727 | } | ||
| 728 | EXPORT_SYMBOL(dump_bfin_trace_buffer); | ||
| 729 | |||
| 730 | void dump_bfin_process(struct pt_regs *fp) | ||
| 731 | { | ||
| 732 | /* We should be able to look at fp->ipend, but we don't push it on the | ||
| 733 | * stack all the time, so do this until we fix that */ | ||
| 734 | unsigned int context = bfin_read_IPEND(); | ||
| 735 | |||
| 736 | if (oops_in_progress) | ||
| 737 | pr_emerg("Kernel OOPS in progress\n"); | ||
| 738 | |||
| 739 | if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) | ||
| 740 | pr_notice("HW Error context\n"); | ||
| 741 | else if (context & 0x0020) | ||
| 742 | pr_notice("Deferred Exception context\n"); | ||
| 743 | else if (context & 0x3FC0) | ||
| 744 | pr_notice("Interrupt context\n"); | ||
| 745 | else if (context & 0x4000) | ||
| 746 | pr_notice("Deferred Interrupt context\n"); | ||
| 747 | else if (context & 0x8000) | ||
| 748 | pr_notice("Kernel process context\n"); | ||
| 749 | |||
| 750 | /* Because we are crashing, and pointers could be bad, we check things | ||
| 751 | * pretty closely before we use them | ||
| 752 | */ | ||
| 753 | if ((unsigned long)current >= FIXED_CODE_START && | ||
| 754 | !((unsigned long)current & 0x3) && current->pid) { | ||
| 755 | pr_notice("CURRENT PROCESS:\n"); | ||
| 756 | if (current->comm >= (char *)FIXED_CODE_START) | ||
| 757 | pr_notice("COMM=%s PID=%d", | ||
| 758 | current->comm, current->pid); | ||
| 759 | else | ||
| 760 | pr_notice("COMM= invalid"); | ||
| 761 | |||
| 762 | pr_cont(" CPU=%d\n", current_thread_info()->cpu); | ||
| 763 | if (!((unsigned long)current->mm & 0x3) && | ||
| 764 | (unsigned long)current->mm >= FIXED_CODE_START) { | ||
| 765 | pr_notice("TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n", | ||
| 766 | (void *)current->mm->start_code, | ||
| 767 | (void *)current->mm->end_code, | ||
| 768 | (void *)current->mm->start_data, | ||
| 769 | (void *)current->mm->end_data); | ||
| 770 | pr_notice(" BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n", | ||
| 771 | (void *)current->mm->end_data, | ||
| 772 | (void *)current->mm->brk, | ||
| 773 | (void *)current->mm->start_stack); | ||
| 774 | } else | ||
| 775 | pr_notice("invalid mm\n"); | ||
| 776 | } else | ||
| 777 | pr_notice("No Valid process in current context\n"); | ||
| 778 | } | ||
| 779 | |||
| 780 | void dump_bfin_mem(struct pt_regs *fp) | ||
| 781 | { | ||
| 782 | unsigned short *addr, *erraddr, val = 0, err = 0; | ||
| 783 | char sti = 0, buf[6]; | ||
| 784 | |||
| 785 | erraddr = (void *)fp->pc; | ||
| 786 | |||
| 787 | pr_notice("return address: [0x%p]; contents of:", erraddr); | ||
| 788 | |||
| 789 | for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10; | ||
| 790 | addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10; | ||
| 791 | addr++) { | ||
| 792 | if (!((unsigned long)addr & 0xF)) | ||
| 793 | pr_notice("0x%p: ", addr); | ||
| 794 | |||
| 795 | if (!get_mem16(&val, addr)) { | ||
| 796 | val = 0; | ||
| 797 | sprintf(buf, "????"); | ||
| 798 | } else | ||
| 799 | sprintf(buf, "%04x", val); | ||
| 800 | |||
| 801 | if (addr == erraddr) { | ||
| 802 | pr_cont("[%s]", buf); | ||
| 803 | err = val; | ||
| 804 | } else | ||
| 805 | pr_cont(" %s ", buf); | ||
| 806 | |||
| 807 | /* Do any previous instructions turn on interrupts? */ | ||
| 808 | if (addr <= erraddr && /* in the past */ | ||
| 809 | ((val >= 0x0040 && val <= 0x0047) || /* STI instruction */ | ||
| 810 | val == 0x017b)) /* [SP++] = RETI */ | ||
| 811 | sti = 1; | ||
| 812 | } | ||
| 813 | |||
| 814 | pr_cont("\n"); | ||
| 815 | |||
| 816 | /* Hardware error interrupts can be deferred */ | ||
| 817 | if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR && | ||
| 818 | oops_in_progress)){ | ||
| 819 | pr_notice("Looks like this was a deferred error - sorry\n"); | ||
| 820 | #ifndef CONFIG_DEBUG_HWERR | ||
| 821 | pr_notice("The remaining message may be meaningless\n"); | ||
| 822 | pr_notice("You should enable CONFIG_DEBUG_HWERR to get a better idea where it came from\n"); | ||
| 823 | #else | ||
| 824 | /* If we are handling only one peripheral interrupt | ||
| 825 | * and current mm and pid are valid, and the last error | ||
| 826 | * was in that user space process's text area | ||
| 827 | * print it out - because that is where the problem exists | ||
| 828 | */ | ||
| 829 | if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) && | ||
| 830 | (current->pid && current->mm)) { | ||
| 831 | /* And the last RETI points to the current userspace context */ | ||
| 832 | if ((fp + 1)->pc >= current->mm->start_code && | ||
| 833 | (fp + 1)->pc <= current->mm->end_code) { | ||
| 834 | pr_notice("It might be better to look around here :\n"); | ||
| 835 | pr_notice("-------------------------------------------\n"); | ||
| 836 | show_regs(fp + 1); | ||
| 837 | pr_notice("-------------------------------------------\n"); | ||
| 838 | } | ||
| 839 | } | ||
| 840 | #endif | ||
| 841 | } | ||
| 842 | } | ||
| 843 | |||
| 844 | void show_regs(struct pt_regs *fp) | ||
| 845 | { | ||
| 846 | char buf[150]; | ||
| 847 | struct irqaction *action; | ||
| 848 | unsigned int i; | ||
| 849 | unsigned long flags = 0; | ||
| 850 | unsigned int cpu = raw_smp_processor_id(); | ||
| 851 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | ||
| 852 | |||
| 853 | pr_notice("\n"); | ||
| 854 | if (CPUID != bfin_cpuid()) | ||
| 855 | pr_notice("Compiled for cpu family 0x%04x (Rev %d), " | ||
| 856 | "but running on:0x%04x (Rev %d)\n", | ||
| 857 | CPUID, bfin_compiled_revid(), bfin_cpuid(), bfin_revid()); | ||
| 858 | |||
| 859 | pr_notice("ADSP-%s-0.%d", | ||
| 860 | CPU, bfin_compiled_revid()); | ||
| 861 | |||
| 862 | if (bfin_compiled_revid() != bfin_revid()) | ||
| 863 | pr_cont("(Detected 0.%d)", bfin_revid()); | ||
| 864 | |||
| 865 | pr_cont(" %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n", | ||
| 866 | get_cclk()/1000000, get_sclk()/1000000, | ||
| 867 | #ifdef CONFIG_MPU | ||
| 868 | "mpu on" | ||
| 869 | #else | ||
| 870 | "mpu off" | ||
| 871 | #endif | ||
| 872 | ); | ||
| 873 | |||
| 874 | pr_notice("%s", linux_banner); | ||
| 875 | |||
| 876 | pr_notice("\nSEQUENCER STATUS:\t\t%s\n", print_tainted()); | ||
| 877 | pr_notice(" SEQSTAT: %08lx IPEND: %04lx IMASK: %04lx SYSCFG: %04lx\n", | ||
| 878 | (long)fp->seqstat, fp->ipend, cpu_pda[raw_smp_processor_id()].ex_imask, fp->syscfg); | ||
| 879 | if (fp->ipend & EVT_IRPTEN) | ||
| 880 | pr_notice(" Global Interrupts Disabled (IPEND[4])\n"); | ||
| 881 | if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG13 | EVT_IVG12 | EVT_IVG11 | | ||
| 882 | EVT_IVG10 | EVT_IVG9 | EVT_IVG8 | EVT_IVG7 | EVT_IVTMR))) | ||
| 883 | pr_notice(" Peripheral interrupts masked off\n"); | ||
| 884 | if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG15 | EVT_IVG14))) | ||
| 885 | pr_notice(" Kernel interrupts masked off\n"); | ||
| 886 | if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) { | ||
| 887 | pr_notice(" HWERRCAUSE: 0x%lx\n", | ||
| 888 | (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14); | ||
| 889 | #ifdef EBIU_ERRMST | ||
| 890 | /* If the error was from the EBIU, print it out */ | ||
| 891 | if (bfin_read_EBIU_ERRMST() & CORE_ERROR) { | ||
| 892 | pr_notice(" EBIU Error Reason : 0x%04x\n", | ||
| 893 | bfin_read_EBIU_ERRMST()); | ||
| 894 | pr_notice(" EBIU Error Address : 0x%08x\n", | ||
| 895 | bfin_read_EBIU_ERRADD()); | ||
| 896 | } | ||
| 897 | #endif | ||
| 898 | } | ||
| 899 | pr_notice(" EXCAUSE : 0x%lx\n", | ||
| 900 | fp->seqstat & SEQSTAT_EXCAUSE); | ||
| 901 | for (i = 2; i <= 15 ; i++) { | ||
| 902 | if (fp->ipend & (1 << i)) { | ||
| 903 | if (i != 4) { | ||
| 904 | decode_address(buf, bfin_read32(EVT0 + 4*i)); | ||
| 905 | pr_notice(" physical IVG%i asserted : %s\n", i, buf); | ||
| 906 | } else | ||
| 907 | pr_notice(" interrupts disabled\n"); | ||
| 908 | } | ||
| 909 | } | ||
| 910 | |||
| 911 | /* if no interrupts are going off, don't print this out */ | ||
| 912 | if (fp->ipend & ~0x3F) { | ||
| 913 | for (i = 0; i < (NR_IRQS - 1); i++) { | ||
| 914 | if (!in_atomic) | ||
| 915 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
| 916 | |||
| 917 | action = irq_desc[i].action; | ||
| 918 | if (!action) | ||
| 919 | goto unlock; | ||
| 920 | |||
| 921 | decode_address(buf, (unsigned int)action->handler); | ||
| 922 | pr_notice(" logical irq %3d mapped : %s", i, buf); | ||
| 923 | for (action = action->next; action; action = action->next) { | ||
| 924 | decode_address(buf, (unsigned int)action->handler); | ||
| 925 | pr_cont(", %s", buf); | ||
| 926 | } | ||
| 927 | pr_cont("\n"); | ||
| 928 | unlock: | ||
| 929 | if (!in_atomic) | ||
| 930 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
| 931 | } | ||
| 932 | } | ||
| 933 | |||
| 934 | decode_address(buf, fp->rete); | ||
| 935 | pr_notice(" RETE: %s\n", buf); | ||
| 936 | decode_address(buf, fp->retn); | ||
| 937 | pr_notice(" RETN: %s\n", buf); | ||
| 938 | decode_address(buf, fp->retx); | ||
| 939 | pr_notice(" RETX: %s\n", buf); | ||
| 940 | decode_address(buf, fp->rets); | ||
| 941 | pr_notice(" RETS: %s\n", buf); | ||
| 942 | decode_address(buf, fp->pc); | ||
| 943 | pr_notice(" PC : %s\n", buf); | ||
| 944 | |||
| 945 | if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && | ||
| 946 | (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { | ||
| 947 | decode_address(buf, cpu_pda[cpu].dcplb_fault_addr); | ||
| 948 | pr_notice("DCPLB_FAULT_ADDR: %s\n", buf); | ||
| 949 | decode_address(buf, cpu_pda[cpu].icplb_fault_addr); | ||
| 950 | pr_notice("ICPLB_FAULT_ADDR: %s\n", buf); | ||
| 951 | } | ||
| 952 | |||
| 953 | pr_notice("PROCESSOR STATE:\n"); | ||
| 954 | pr_notice(" R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", | ||
| 955 | fp->r0, fp->r1, fp->r2, fp->r3); | ||
| 956 | pr_notice(" R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", | ||
| 957 | fp->r4, fp->r5, fp->r6, fp->r7); | ||
| 958 | pr_notice(" P0 : %08lx P1 : %08lx P2 : %08lx P3 : %08lx\n", | ||
| 959 | fp->p0, fp->p1, fp->p2, fp->p3); | ||
| 960 | pr_notice(" P4 : %08lx P5 : %08lx FP : %08lx SP : %08lx\n", | ||
| 961 | fp->p4, fp->p5, fp->fp, (long)fp); | ||
| 962 | pr_notice(" LB0: %08lx LT0: %08lx LC0: %08lx\n", | ||
| 963 | fp->lb0, fp->lt0, fp->lc0); | ||
| 964 | pr_notice(" LB1: %08lx LT1: %08lx LC1: %08lx\n", | ||
| 965 | fp->lb1, fp->lt1, fp->lc1); | ||
| 966 | pr_notice(" B0 : %08lx L0 : %08lx M0 : %08lx I0 : %08lx\n", | ||
| 967 | fp->b0, fp->l0, fp->m0, fp->i0); | ||
| 968 | pr_notice(" B1 : %08lx L1 : %08lx M1 : %08lx I1 : %08lx\n", | ||
| 969 | fp->b1, fp->l1, fp->m1, fp->i1); | ||
| 970 | pr_notice(" B2 : %08lx L2 : %08lx M2 : %08lx I2 : %08lx\n", | ||
| 971 | fp->b2, fp->l2, fp->m2, fp->i2); | ||
| 972 | pr_notice(" B3 : %08lx L3 : %08lx M3 : %08lx I3 : %08lx\n", | ||
| 973 | fp->b3, fp->l3, fp->m3, fp->i3); | ||
| 974 | pr_notice("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", | ||
| 975 | fp->a0w, fp->a0x, fp->a1w, fp->a1x); | ||
| 976 | |||
| 977 | pr_notice("USP : %08lx ASTAT: %08lx\n", | ||
| 978 | rdusp(), fp->astat); | ||
| 979 | |||
| 980 | pr_notice("\n"); | ||
| 981 | } | ||
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index ba70c4bc2699..59c1df75e4de 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c | |||
| @@ -1,25 +1,22 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright 2004-2009 Analog Devices Inc. | 2 | * Main exception handling logic. |
| 3 | * | ||
| 4 | * Copyright 2004-2010 Analog Devices Inc. | ||
| 3 | * | 5 | * |
| 4 | * Licensed under the GPL-2 or later | 6 | * Licensed under the GPL-2 or later |
| 5 | */ | 7 | */ |
| 6 | 8 | ||
| 7 | #include <linux/bug.h> | 9 | #include <linux/bug.h> |
| 8 | #include <linux/uaccess.h> | 10 | #include <linux/uaccess.h> |
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 11 | #include <linux/kallsyms.h> | ||
| 12 | #include <linux/fs.h> | ||
| 13 | #include <linux/rbtree.h> | ||
| 14 | #include <asm/traps.h> | 12 | #include <asm/traps.h> |
| 15 | #include <asm/cacheflush.h> | ||
| 16 | #include <asm/cplb.h> | 13 | #include <asm/cplb.h> |
| 17 | #include <asm/dma.h> | ||
| 18 | #include <asm/blackfin.h> | 14 | #include <asm/blackfin.h> |
| 19 | #include <asm/irq_handler.h> | 15 | #include <asm/irq_handler.h> |
| 20 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
| 21 | #include <asm/trace.h> | 17 | #include <asm/trace.h> |
| 22 | #include <asm/fixed_code.h> | 18 | #include <asm/fixed_code.h> |
| 19 | #include <asm/pseudo_instructions.h> | ||
| 23 | 20 | ||
| 24 | #ifdef CONFIG_KGDB | 21 | #ifdef CONFIG_KGDB |
| 25 | # include <linux/kgdb.h> | 22 | # include <linux/kgdb.h> |
| @@ -62,194 +59,6 @@ void __init trap_init(void) | |||
| 62 | CSYNC(); | 59 | CSYNC(); |
| 63 | } | 60 | } |
| 64 | 61 | ||
| 65 | static void decode_address(char *buf, unsigned long address) | ||
| 66 | { | ||
| 67 | #ifdef CONFIG_DEBUG_VERBOSE | ||
| 68 | struct task_struct *p; | ||
| 69 | struct mm_struct *mm; | ||
| 70 | unsigned long flags, offset; | ||
| 71 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | ||
| 72 | struct rb_node *n; | ||
| 73 | |||
| 74 | #ifdef CONFIG_KALLSYMS | ||
| 75 | unsigned long symsize; | ||
| 76 | const char *symname; | ||
| 77 | char *modname; | ||
| 78 | char *delim = ":"; | ||
| 79 | char namebuf[128]; | ||
| 80 | #endif | ||
| 81 | |||
| 82 | buf += sprintf(buf, "<0x%08lx> ", address); | ||
| 83 | |||
| 84 | #ifdef CONFIG_KALLSYMS | ||
| 85 | /* look up the address and see if we are in kernel space */ | ||
| 86 | symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf); | ||
| 87 | |||
| 88 | if (symname) { | ||
| 89 | /* yeah! kernel space! */ | ||
| 90 | if (!modname) | ||
| 91 | modname = delim = ""; | ||
| 92 | sprintf(buf, "{ %s%s%s%s + 0x%lx }", | ||
| 93 | delim, modname, delim, symname, | ||
| 94 | (unsigned long)offset); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | #endif | ||
| 98 | |||
| 99 | if (address >= FIXED_CODE_START && address < FIXED_CODE_END) { | ||
| 100 | /* Problem in fixed code section? */ | ||
| 101 | strcat(buf, "/* Maybe fixed code section */"); | ||
| 102 | return; | ||
| 103 | |||
| 104 | } else if (address < CONFIG_BOOT_LOAD) { | ||
| 105 | /* Problem somewhere before the kernel start address */ | ||
| 106 | strcat(buf, "/* Maybe null pointer? */"); | ||
| 107 | return; | ||
| 108 | |||
| 109 | } else if (address >= COREMMR_BASE) { | ||
| 110 | strcat(buf, "/* core mmrs */"); | ||
| 111 | return; | ||
| 112 | |||
| 113 | } else if (address >= SYSMMR_BASE) { | ||
| 114 | strcat(buf, "/* system mmrs */"); | ||
| 115 | return; | ||
| 116 | |||
| 117 | } else if (address >= L1_ROM_START && address < L1_ROM_START + L1_ROM_LENGTH) { | ||
| 118 | strcat(buf, "/* on-chip L1 ROM */"); | ||
| 119 | return; | ||
| 120 | } | ||
| 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 | |||
| 131 | /* looks like we're off in user-land, so let's walk all the | ||
| 132 | * mappings of all our processes and see if we can't be a whee | ||
| 133 | * bit more specific | ||
| 134 | */ | ||
| 135 | write_lock_irqsave(&tasklist_lock, flags); | ||
| 136 | for_each_process(p) { | ||
| 137 | mm = (in_atomic ? p->mm : get_task_mm(p)); | ||
| 138 | if (!mm) | ||
| 139 | continue; | ||
| 140 | |||
| 141 | if (!down_read_trylock(&mm->mmap_sem)) { | ||
| 142 | if (!in_atomic) | ||
| 143 | mmput(mm); | ||
| 144 | continue; | ||
| 145 | } | ||
| 146 | |||
| 147 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { | ||
| 148 | struct vm_area_struct *vma; | ||
| 149 | |||
| 150 | vma = rb_entry(n, struct vm_area_struct, vm_rb); | ||
| 151 | |||
| 152 | if (address >= vma->vm_start && address < vma->vm_end) { | ||
| 153 | char _tmpbuf[256]; | ||
| 154 | char *name = p->comm; | ||
| 155 | struct file *file = vma->vm_file; | ||
| 156 | |||
| 157 | if (file) { | ||
| 158 | char *d_name = d_path(&file->f_path, _tmpbuf, | ||
| 159 | sizeof(_tmpbuf)); | ||
| 160 | if (!IS_ERR(d_name)) | ||
| 161 | name = d_name; | ||
| 162 | } | ||
| 163 | |||
| 164 | /* FLAT does not have its text aligned to the start of | ||
| 165 | * the map while FDPIC ELF does ... | ||
| 166 | */ | ||
| 167 | |||
| 168 | /* before we can check flat/fdpic, we need to | ||
| 169 | * make sure current is valid | ||
| 170 | */ | ||
| 171 | if ((unsigned long)current >= FIXED_CODE_START && | ||
| 172 | !((unsigned long)current & 0x3)) { | ||
| 173 | if (current->mm && | ||
| 174 | (address > current->mm->start_code) && | ||
| 175 | (address < current->mm->end_code)) | ||
| 176 | offset = address - current->mm->start_code; | ||
| 177 | else | ||
| 178 | offset = (address - vma->vm_start) + | ||
| 179 | (vma->vm_pgoff << PAGE_SHIFT); | ||
| 180 | |||
| 181 | sprintf(buf, "[ %s + 0x%lx ]", name, offset); | ||
| 182 | } else | ||
| 183 | sprintf(buf, "[ %s vma:0x%lx-0x%lx]", | ||
| 184 | name, vma->vm_start, vma->vm_end); | ||
| 185 | |||
| 186 | up_read(&mm->mmap_sem); | ||
| 187 | if (!in_atomic) | ||
| 188 | mmput(mm); | ||
| 189 | |||
| 190 | if (buf[0] == '\0') | ||
| 191 | sprintf(buf, "[ %s ] dynamic memory", name); | ||
| 192 | |||
| 193 | goto done; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | up_read(&mm->mmap_sem); | ||
| 198 | if (!in_atomic) | ||
| 199 | mmput(mm); | ||
| 200 | } | ||
| 201 | |||
| 202 | /* | ||
| 203 | * we were unable to find this address anywhere, | ||
| 204 | * or some MMs were skipped because they were in use. | ||
| 205 | */ | ||
| 206 | sprintf(buf, "/* kernel dynamic memory */"); | ||
| 207 | |||
| 208 | done: | ||
| 209 | write_unlock_irqrestore(&tasklist_lock, flags); | ||
| 210 | #else | ||
| 211 | sprintf(buf, " "); | ||
| 212 | #endif | ||
| 213 | } | ||
| 214 | |||
| 215 | asmlinkage void double_fault_c(struct pt_regs *fp) | ||
| 216 | { | ||
| 217 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
| 218 | int j; | ||
| 219 | trace_buffer_save(j); | ||
| 220 | #endif | ||
| 221 | |||
| 222 | console_verbose(); | ||
| 223 | oops_in_progress = 1; | ||
| 224 | #ifdef CONFIG_DEBUG_VERBOSE | ||
| 225 | printk(KERN_EMERG "Double Fault\n"); | ||
| 226 | #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT | ||
| 227 | if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { | ||
| 228 | unsigned int cpu = raw_smp_processor_id(); | ||
| 229 | char buf[150]; | ||
| 230 | decode_address(buf, cpu_pda[cpu].retx_doublefault); | ||
| 231 | printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", | ||
| 232 | (unsigned int)cpu_pda[cpu].seqstat_doublefault & SEQSTAT_EXCAUSE, buf); | ||
| 233 | decode_address(buf, cpu_pda[cpu].dcplb_doublefault_addr); | ||
| 234 | printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); | ||
| 235 | decode_address(buf, cpu_pda[cpu].icplb_doublefault_addr); | ||
| 236 | printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); | ||
| 237 | |||
| 238 | decode_address(buf, fp->retx); | ||
| 239 | printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf); | ||
| 240 | } else | ||
| 241 | #endif | ||
| 242 | { | ||
| 243 | dump_bfin_process(fp); | ||
| 244 | dump_bfin_mem(fp); | ||
| 245 | show_regs(fp); | ||
| 246 | dump_bfin_trace_buffer(); | ||
| 247 | } | ||
| 248 | #endif | ||
| 249 | panic("Double Fault - unrecoverable event"); | ||
| 250 | |||
| 251 | } | ||
| 252 | |||
| 253 | static int kernel_mode_regs(struct pt_regs *regs) | 62 | static int kernel_mode_regs(struct pt_regs *regs) |
| 254 | { | 63 | { |
| 255 | return regs->ipend & 0xffc0; | 64 | return regs->ipend & 0xffc0; |
| @@ -260,6 +69,9 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
| 260 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 69 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
| 261 | int j; | 70 | int j; |
| 262 | #endif | 71 | #endif |
| 72 | #ifdef CONFIG_BFIN_PSEUDODBG_INSNS | ||
| 73 | int opcode; | ||
| 74 | #endif | ||
| 263 | unsigned int cpu = raw_smp_processor_id(); | 75 | unsigned int cpu = raw_smp_processor_id(); |
| 264 | const char *strerror = NULL; | 76 | const char *strerror = NULL; |
| 265 | int sig = 0; | 77 | int sig = 0; |
| @@ -392,6 +204,19 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
| 392 | } | 204 | } |
| 393 | } | 205 | } |
| 394 | #endif | 206 | #endif |
| 207 | #ifdef CONFIG_BFIN_PSEUDODBG_INSNS | ||
| 208 | /* | ||
| 209 | * Support for the fake instructions, if the instruction fails, | ||
| 210 | * then just execute a illegal opcode failure (like normal). | ||
| 211 | * Don't support these instructions inside the kernel | ||
| 212 | */ | ||
| 213 | if (!kernel_mode_regs(fp) && get_instruction(&opcode, (unsigned short *)fp->pc)) { | ||
| 214 | if (execute_pseudodbg_assert(fp, opcode)) | ||
| 215 | goto traps_done; | ||
| 216 | if (execute_pseudodbg(fp, opcode)) | ||
| 217 | goto traps_done; | ||
| 218 | } | ||
| 219 | #endif | ||
| 395 | info.si_code = ILL_ILLOPC; | 220 | info.si_code = ILL_ILLOPC; |
| 396 | sig = SIGILL; | 221 | sig = SIGILL; |
| 397 | strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE); | 222 | strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE); |
| @@ -672,659 +497,44 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) | |||
| 672 | trace_buffer_restore(j); | 497 | trace_buffer_restore(j); |
| 673 | } | 498 | } |
| 674 | 499 | ||
| 675 | /* Typical exception handling routines */ | 500 | asmlinkage void double_fault_c(struct pt_regs *fp) |
| 676 | |||
| 677 | #define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1) | ||
| 678 | |||
| 679 | /* | ||
| 680 | * Similar to get_user, do some address checking, then dereference | ||
| 681 | * Return true on success, false on bad address | ||
| 682 | */ | ||
| 683 | static bool get_instruction(unsigned short *val, unsigned short *address) | ||
| 684 | { | ||
| 685 | unsigned long addr = (unsigned long)address; | ||
| 686 | |||
| 687 | /* Check for odd addresses */ | ||
| 688 | if (addr & 0x1) | ||
| 689 | return false; | ||
| 690 | |||
| 691 | /* MMR region will never have instructions */ | ||
| 692 | if (addr >= SYSMMR_BASE) | ||
| 693 | return false; | ||
| 694 | |||
| 695 | switch (bfin_mem_access_type(addr, 2)) { | ||
| 696 | case BFIN_MEM_ACCESS_CORE: | ||
| 697 | case BFIN_MEM_ACCESS_CORE_ONLY: | ||
| 698 | *val = *address; | ||
| 699 | return true; | ||
| 700 | case BFIN_MEM_ACCESS_DMA: | ||
| 701 | dma_memcpy(val, address, 2); | ||
| 702 | return true; | ||
| 703 | case BFIN_MEM_ACCESS_ITEST: | ||
| 704 | isram_memcpy(val, address, 2); | ||
| 705 | return true; | ||
| 706 | default: /* invalid access */ | ||
| 707 | return false; | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 711 | /* | ||
| 712 | * decode the instruction if we are printing out the trace, as it | ||
| 713 | * makes things easier to follow, without running it through objdump | ||
| 714 | * These are the normal instructions which cause change of flow, which | ||
| 715 | * would be at the source of the trace buffer | ||
| 716 | */ | ||
| 717 | #if defined(CONFIG_DEBUG_VERBOSE) && defined(CONFIG_DEBUG_BFIN_HWTRACE_ON) | ||
| 718 | static void decode_instruction(unsigned short *address) | ||
| 719 | { | ||
| 720 | unsigned short opcode; | ||
| 721 | |||
| 722 | if (get_instruction(&opcode, address)) { | ||
| 723 | if (opcode == 0x0010) | ||
| 724 | verbose_printk("RTS"); | ||
| 725 | else if (opcode == 0x0011) | ||
| 726 | verbose_printk("RTI"); | ||
| 727 | else if (opcode == 0x0012) | ||
| 728 | verbose_printk("RTX"); | ||
| 729 | else if (opcode == 0x0013) | ||
| 730 | verbose_printk("RTN"); | ||
| 731 | else if (opcode == 0x0014) | ||
| 732 | verbose_printk("RTE"); | ||
| 733 | else if (opcode == 0x0025) | ||
| 734 | verbose_printk("EMUEXCPT"); | ||
| 735 | else if (opcode >= 0x0040 && opcode <= 0x0047) | ||
| 736 | verbose_printk("STI R%i", opcode & 7); | ||
| 737 | else if (opcode >= 0x0050 && opcode <= 0x0057) | ||
| 738 | verbose_printk("JUMP (P%i)", opcode & 7); | ||
| 739 | else if (opcode >= 0x0060 && opcode <= 0x0067) | ||
| 740 | verbose_printk("CALL (P%i)", opcode & 7); | ||
| 741 | else if (opcode >= 0x0070 && opcode <= 0x0077) | ||
| 742 | verbose_printk("CALL (PC+P%i)", opcode & 7); | ||
| 743 | else if (opcode >= 0x0080 && opcode <= 0x0087) | ||
| 744 | verbose_printk("JUMP (PC+P%i)", opcode & 7); | ||
| 745 | else if (opcode >= 0x0090 && opcode <= 0x009F) | ||
| 746 | verbose_printk("RAISE 0x%x", opcode & 0xF); | ||
| 747 | else if (opcode >= 0x00A0 && opcode <= 0x00AF) | ||
| 748 | verbose_printk("EXCPT 0x%x", opcode & 0xF); | ||
| 749 | else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF)) | ||
| 750 | verbose_printk("IF !CC JUMP"); | ||
| 751 | else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff)) | ||
| 752 | verbose_printk("IF CC JUMP"); | ||
| 753 | else if (opcode >= 0x2000 && opcode <= 0x2fff) | ||
| 754 | verbose_printk("JUMP.S"); | ||
| 755 | else if (opcode >= 0xe080 && opcode <= 0xe0ff) | ||
| 756 | verbose_printk("LSETUP"); | ||
| 757 | else if (opcode >= 0xe200 && opcode <= 0xe2ff) | ||
| 758 | verbose_printk("JUMP.L"); | ||
| 759 | else if (opcode >= 0xe300 && opcode <= 0xe3ff) | ||
| 760 | verbose_printk("CALL pcrel"); | ||
| 761 | else | ||
| 762 | verbose_printk("0x%04x", opcode); | ||
| 763 | } | ||
| 764 | |||
| 765 | } | ||
| 766 | #endif | ||
| 767 | |||
| 768 | void dump_bfin_trace_buffer(void) | ||
| 769 | { | ||
| 770 | #ifdef CONFIG_DEBUG_VERBOSE | ||
| 771 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | ||
| 772 | int tflags, i = 0; | ||
| 773 | char buf[150]; | ||
| 774 | unsigned short *addr; | ||
| 775 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
| 776 | int j, index; | ||
| 777 | #endif | ||
| 778 | |||
| 779 | trace_buffer_save(tflags); | ||
| 780 | |||
| 781 | printk(KERN_NOTICE "Hardware Trace:\n"); | ||
| 782 | |||
| 783 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
| 784 | printk(KERN_NOTICE "WARNING: Expanded trace turned on - can not trace exceptions\n"); | ||
| 785 | #endif | ||
| 786 | |||
| 787 | if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { | ||
| 788 | for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) { | ||
| 789 | decode_address(buf, (unsigned long)bfin_read_TBUF()); | ||
| 790 | printk(KERN_NOTICE "%4i Target : %s\n", i, buf); | ||
| 791 | addr = (unsigned short *)bfin_read_TBUF(); | ||
| 792 | decode_address(buf, (unsigned long)addr); | ||
| 793 | printk(KERN_NOTICE " Source : %s ", buf); | ||
| 794 | decode_instruction(addr); | ||
| 795 | printk("\n"); | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND | ||
| 800 | if (trace_buff_offset) | ||
| 801 | index = trace_buff_offset / 4; | ||
| 802 | else | ||
| 803 | index = EXPAND_LEN; | ||
| 804 | |||
| 805 | j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128; | ||
| 806 | while (j) { | ||
| 807 | decode_address(buf, software_trace_buff[index]); | ||
| 808 | printk(KERN_NOTICE "%4i Target : %s\n", i, buf); | ||
| 809 | index -= 1; | ||
| 810 | if (index < 0 ) | ||
| 811 | index = EXPAND_LEN; | ||
| 812 | decode_address(buf, software_trace_buff[index]); | ||
| 813 | printk(KERN_NOTICE " Source : %s ", buf); | ||
| 814 | decode_instruction((unsigned short *)software_trace_buff[index]); | ||
| 815 | printk("\n"); | ||
| 816 | index -= 1; | ||
| 817 | if (index < 0) | ||
| 818 | index = EXPAND_LEN; | ||
| 819 | j--; | ||
| 820 | i++; | ||
| 821 | } | ||
| 822 | #endif | ||
| 823 | |||
| 824 | trace_buffer_restore(tflags); | ||
| 825 | #endif | ||
| 826 | #endif | ||
| 827 | } | ||
| 828 | EXPORT_SYMBOL(dump_bfin_trace_buffer); | ||
| 829 | |||
| 830 | #ifdef CONFIG_BUG | ||
| 831 | int is_valid_bugaddr(unsigned long addr) | ||
| 832 | { | ||
| 833 | unsigned short opcode; | ||
| 834 | |||
| 835 | if (!get_instruction(&opcode, (unsigned short *)addr)) | ||
| 836 | return 0; | ||
| 837 | |||
| 838 | return opcode == BFIN_BUG_OPCODE; | ||
| 839 | } | ||
| 840 | #endif | ||
| 841 | |||
| 842 | /* | ||
| 843 | * Checks to see if the address pointed to is either a | ||
| 844 | * 16-bit CALL instruction, or a 32-bit CALL instruction | ||
| 845 | */ | ||
| 846 | static bool is_bfin_call(unsigned short *addr) | ||
| 847 | { | ||
| 848 | unsigned short opcode = 0, *ins_addr; | ||
| 849 | ins_addr = (unsigned short *)addr; | ||
| 850 | |||
| 851 | if (!get_instruction(&opcode, ins_addr)) | ||
| 852 | return false; | ||
| 853 | |||
| 854 | if ((opcode >= 0x0060 && opcode <= 0x0067) || | ||
| 855 | (opcode >= 0x0070 && opcode <= 0x0077)) | ||
| 856 | return true; | ||
| 857 | |||
| 858 | ins_addr--; | ||
| 859 | if (!get_instruction(&opcode, ins_addr)) | ||
| 860 | return false; | ||
| 861 | |||
| 862 | if (opcode >= 0xE300 && opcode <= 0xE3FF) | ||
| 863 | return true; | ||
| 864 | |||
| 865 | return false; | ||
| 866 | |||
| 867 | } | ||
| 868 | |||
| 869 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
| 870 | { | ||
| 871 | #ifdef CONFIG_PRINTK | ||
| 872 | unsigned int *addr, *endstack, *fp = 0, *frame; | ||
| 873 | unsigned short *ins_addr; | ||
| 874 | char buf[150]; | ||
| 875 | unsigned int i, j, ret_addr, frame_no = 0; | ||
| 876 | |||
| 877 | /* | ||
| 878 | * If we have been passed a specific stack, use that one otherwise | ||
| 879 | * if we have been passed a task structure, use that, otherwise | ||
| 880 | * use the stack of where the variable "stack" exists | ||
| 881 | */ | ||
| 882 | |||
| 883 | if (stack == NULL) { | ||
| 884 | if (task) { | ||
| 885 | /* We know this is a kernel stack, so this is the start/end */ | ||
| 886 | stack = (unsigned long *)task->thread.ksp; | ||
| 887 | endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE); | ||
| 888 | } else { | ||
| 889 | /* print out the existing stack info */ | ||
| 890 | stack = (unsigned long *)&stack; | ||
| 891 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | ||
| 892 | } | ||
| 893 | } else | ||
| 894 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | ||
| 895 | |||
| 896 | printk(KERN_NOTICE "Stack info:\n"); | ||
| 897 | decode_address(buf, (unsigned int)stack); | ||
| 898 | printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); | ||
| 899 | |||
| 900 | if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) { | ||
| 901 | printk(KERN_NOTICE "Invalid stack pointer\n"); | ||
| 902 | return; | ||
| 903 | } | ||
| 904 | |||
| 905 | /* First thing is to look for a frame pointer */ | ||
| 906 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) { | ||
| 907 | if (*addr & 0x1) | ||
| 908 | continue; | ||
| 909 | ins_addr = (unsigned short *)*addr; | ||
| 910 | ins_addr--; | ||
| 911 | if (is_bfin_call(ins_addr)) | ||
| 912 | fp = addr - 1; | ||
| 913 | |||
| 914 | if (fp) { | ||
| 915 | /* Let's check to see if it is a frame pointer */ | ||
| 916 | while (fp >= (addr - 1) && fp < endstack | ||
| 917 | && fp && ((unsigned int) fp & 0x3) == 0) | ||
| 918 | fp = (unsigned int *)*fp; | ||
| 919 | if (fp == 0 || fp == endstack) { | ||
| 920 | fp = addr - 1; | ||
| 921 | break; | ||
| 922 | } | ||
| 923 | fp = 0; | ||
| 924 | } | ||
| 925 | } | ||
| 926 | if (fp) { | ||
| 927 | frame = fp; | ||
| 928 | printk(KERN_NOTICE " FP: (0x%p)\n", fp); | ||
| 929 | } else | ||
| 930 | frame = 0; | ||
| 931 | |||
| 932 | /* | ||
| 933 | * Now that we think we know where things are, we | ||
| 934 | * walk the stack again, this time printing things out | ||
| 935 | * incase there is no frame pointer, we still look for | ||
| 936 | * valid return addresses | ||
| 937 | */ | ||
| 938 | |||
| 939 | /* First time print out data, next time, print out symbols */ | ||
| 940 | for (j = 0; j <= 1; j++) { | ||
| 941 | if (j) | ||
| 942 | printk(KERN_NOTICE "Return addresses in stack:\n"); | ||
| 943 | else | ||
| 944 | printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack); | ||
| 945 | |||
| 946 | fp = frame; | ||
| 947 | frame_no = 0; | ||
| 948 | |||
| 949 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0; | ||
| 950 | addr < endstack; addr++, i++) { | ||
| 951 | |||
| 952 | ret_addr = 0; | ||
| 953 | if (!j && i % 8 == 0) | ||
| 954 | printk(KERN_NOTICE "%p:",addr); | ||
| 955 | |||
| 956 | /* if it is an odd address, or zero, just skip it */ | ||
| 957 | if (*addr & 0x1 || !*addr) | ||
| 958 | goto print; | ||
| 959 | |||
| 960 | ins_addr = (unsigned short *)*addr; | ||
| 961 | |||
| 962 | /* Go back one instruction, and see if it is a CALL */ | ||
| 963 | ins_addr--; | ||
| 964 | ret_addr = is_bfin_call(ins_addr); | ||
| 965 | print: | ||
| 966 | if (!j && stack == (unsigned long *)addr) | ||
| 967 | printk("[%08x]", *addr); | ||
| 968 | else if (ret_addr) | ||
| 969 | if (j) { | ||
| 970 | decode_address(buf, (unsigned int)*addr); | ||
| 971 | if (frame == addr) { | ||
| 972 | printk(KERN_NOTICE " frame %2i : %s\n", frame_no, buf); | ||
| 973 | continue; | ||
| 974 | } | ||
| 975 | printk(KERN_NOTICE " address : %s\n", buf); | ||
| 976 | } else | ||
| 977 | printk("<%08x>", *addr); | ||
| 978 | else if (fp == addr) { | ||
| 979 | if (j) | ||
| 980 | frame = addr+1; | ||
| 981 | else | ||
| 982 | printk("(%08x)", *addr); | ||
| 983 | |||
| 984 | fp = (unsigned int *)*addr; | ||
| 985 | frame_no++; | ||
| 986 | |||
| 987 | } else if (!j) | ||
| 988 | printk(" %08x ", *addr); | ||
| 989 | } | ||
| 990 | if (!j) | ||
| 991 | printk("\n"); | ||
| 992 | } | ||
| 993 | #endif | ||
| 994 | } | ||
| 995 | EXPORT_SYMBOL(show_stack); | ||
| 996 | |||
| 997 | void dump_stack(void) | ||
| 998 | { | 501 | { |
| 999 | unsigned long stack; | ||
| 1000 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | 502 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON |
| 1001 | int tflags; | 503 | int j; |
| 504 | trace_buffer_save(j); | ||
| 1002 | #endif | 505 | #endif |
| 1003 | trace_buffer_save(tflags); | ||
| 1004 | dump_bfin_trace_buffer(); | ||
| 1005 | show_stack(current, &stack); | ||
| 1006 | trace_buffer_restore(tflags); | ||
| 1007 | } | ||
| 1008 | EXPORT_SYMBOL(dump_stack); | ||
| 1009 | 506 | ||
| 1010 | void dump_bfin_process(struct pt_regs *fp) | 507 | console_verbose(); |
| 1011 | { | 508 | oops_in_progress = 1; |
| 1012 | #ifdef CONFIG_DEBUG_VERBOSE | 509 | #ifdef CONFIG_DEBUG_VERBOSE |
| 1013 | /* We should be able to look at fp->ipend, but we don't push it on the | 510 | printk(KERN_EMERG "Double Fault\n"); |
| 1014 | * stack all the time, so do this until we fix that */ | 511 | #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT |
| 1015 | unsigned int context = bfin_read_IPEND(); | 512 | if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { |
| 1016 | 513 | unsigned int cpu = raw_smp_processor_id(); | |
| 1017 | if (oops_in_progress) | 514 | char buf[150]; |
| 1018 | verbose_printk(KERN_EMERG "Kernel OOPS in progress\n"); | 515 | decode_address(buf, cpu_pda[cpu].retx_doublefault); |
| 1019 | 516 | printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", | |
| 1020 | if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) | 517 | (unsigned int)cpu_pda[cpu].seqstat_doublefault & SEQSTAT_EXCAUSE, buf); |
| 1021 | verbose_printk(KERN_NOTICE "HW Error context\n"); | 518 | decode_address(buf, cpu_pda[cpu].dcplb_doublefault_addr); |
| 1022 | else if (context & 0x0020) | 519 | printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); |
| 1023 | verbose_printk(KERN_NOTICE "Deferred Exception context\n"); | 520 | decode_address(buf, cpu_pda[cpu].icplb_doublefault_addr); |
| 1024 | else if (context & 0x3FC0) | 521 | printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); |
| 1025 | verbose_printk(KERN_NOTICE "Interrupt context\n"); | ||
| 1026 | else if (context & 0x4000) | ||
| 1027 | verbose_printk(KERN_NOTICE "Deferred Interrupt context\n"); | ||
| 1028 | else if (context & 0x8000) | ||
| 1029 | verbose_printk(KERN_NOTICE "Kernel process context\n"); | ||
| 1030 | |||
| 1031 | /* Because we are crashing, and pointers could be bad, we check things | ||
| 1032 | * pretty closely before we use them | ||
| 1033 | */ | ||
| 1034 | if ((unsigned long)current >= FIXED_CODE_START && | ||
| 1035 | !((unsigned long)current & 0x3) && current->pid) { | ||
| 1036 | verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); | ||
| 1037 | if (current->comm >= (char *)FIXED_CODE_START) | ||
| 1038 | verbose_printk(KERN_NOTICE "COMM=%s PID=%d", | ||
| 1039 | current->comm, current->pid); | ||
| 1040 | else | ||
| 1041 | verbose_printk(KERN_NOTICE "COMM= invalid"); | ||
| 1042 | 522 | ||
| 1043 | printk(KERN_CONT " CPU=%d\n", current_thread_info()->cpu); | 523 | decode_address(buf, fp->retx); |
| 1044 | if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) | 524 | printk(KERN_NOTICE "The instruction at %s caused a double exception\n", buf); |
| 1045 | verbose_printk(KERN_NOTICE | ||
| 1046 | "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" | ||
| 1047 | " BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n", | ||
| 1048 | (void *)current->mm->start_code, | ||
| 1049 | (void *)current->mm->end_code, | ||
| 1050 | (void *)current->mm->start_data, | ||
| 1051 | (void *)current->mm->end_data, | ||
| 1052 | (void *)current->mm->end_data, | ||
| 1053 | (void *)current->mm->brk, | ||
| 1054 | (void *)current->mm->start_stack); | ||
| 1055 | else | ||
| 1056 | verbose_printk(KERN_NOTICE "invalid mm\n"); | ||
| 1057 | } else | 525 | } else |
| 1058 | verbose_printk(KERN_NOTICE | ||
| 1059 | "No Valid process in current context\n"); | ||
| 1060 | #endif | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | void dump_bfin_mem(struct pt_regs *fp) | ||
| 1064 | { | ||
| 1065 | #ifdef CONFIG_DEBUG_VERBOSE | ||
| 1066 | unsigned short *addr, *erraddr, val = 0, err = 0; | ||
| 1067 | char sti = 0, buf[6]; | ||
| 1068 | |||
| 1069 | erraddr = (void *)fp->pc; | ||
| 1070 | |||
| 1071 | verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr); | ||
| 1072 | |||
| 1073 | for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10; | ||
| 1074 | addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10; | ||
| 1075 | addr++) { | ||
| 1076 | if (!((unsigned long)addr & 0xF)) | ||
| 1077 | verbose_printk(KERN_NOTICE "0x%p: ", addr); | ||
| 1078 | |||
| 1079 | if (!get_instruction(&val, addr)) { | ||
| 1080 | val = 0; | ||
| 1081 | sprintf(buf, "????"); | ||
| 1082 | } else | ||
| 1083 | sprintf(buf, "%04x", val); | ||
| 1084 | |||
| 1085 | if (addr == erraddr) { | ||
| 1086 | verbose_printk("[%s]", buf); | ||
| 1087 | err = val; | ||
| 1088 | } else | ||
| 1089 | verbose_printk(" %s ", buf); | ||
| 1090 | |||
| 1091 | /* Do any previous instructions turn on interrupts? */ | ||
| 1092 | if (addr <= erraddr && /* in the past */ | ||
| 1093 | ((val >= 0x0040 && val <= 0x0047) || /* STI instruction */ | ||
| 1094 | val == 0x017b)) /* [SP++] = RETI */ | ||
| 1095 | sti = 1; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | verbose_printk("\n"); | ||
| 1099 | |||
| 1100 | /* Hardware error interrupts can be deferred */ | ||
| 1101 | if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR && | ||
| 1102 | oops_in_progress)){ | ||
| 1103 | verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n"); | ||
| 1104 | #ifndef CONFIG_DEBUG_HWERR | ||
| 1105 | verbose_printk(KERN_NOTICE | ||
| 1106 | "The remaining message may be meaningless\n" | ||
| 1107 | "You should enable CONFIG_DEBUG_HWERR to get a better idea where it came from\n"); | ||
| 1108 | #else | ||
| 1109 | /* If we are handling only one peripheral interrupt | ||
| 1110 | * and current mm and pid are valid, and the last error | ||
| 1111 | * was in that user space process's text area | ||
| 1112 | * print it out - because that is where the problem exists | ||
| 1113 | */ | ||
| 1114 | if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) && | ||
| 1115 | (current->pid && current->mm)) { | ||
| 1116 | /* And the last RETI points to the current userspace context */ | ||
| 1117 | if ((fp + 1)->pc >= current->mm->start_code && | ||
| 1118 | (fp + 1)->pc <= current->mm->end_code) { | ||
| 1119 | verbose_printk(KERN_NOTICE "It might be better to look around here :\n"); | ||
| 1120 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); | ||
| 1121 | show_regs(fp + 1); | ||
| 1122 | verbose_printk(KERN_NOTICE "-------------------------------------------\n"); | ||
| 1123 | } | ||
| 1124 | } | ||
| 1125 | #endif | ||
| 1126 | } | ||
| 1127 | #endif | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | void show_regs(struct pt_regs *fp) | ||
| 1131 | { | ||
| 1132 | #ifdef CONFIG_DEBUG_VERBOSE | ||
| 1133 | char buf [150]; | ||
| 1134 | struct irqaction *action; | ||
| 1135 | unsigned int i; | ||
| 1136 | unsigned long flags = 0; | ||
| 1137 | unsigned int cpu = raw_smp_processor_id(); | ||
| 1138 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | ||
| 1139 | |||
| 1140 | verbose_printk(KERN_NOTICE "\n"); | ||
| 1141 | if (CPUID != bfin_cpuid()) | ||
| 1142 | verbose_printk(KERN_NOTICE "Compiled for cpu family 0x%04x (Rev %d), " | ||
| 1143 | "but running on:0x%04x (Rev %d)\n", | ||
| 1144 | CPUID, bfin_compiled_revid(), bfin_cpuid(), bfin_revid()); | ||
| 1145 | |||
| 1146 | verbose_printk(KERN_NOTICE "ADSP-%s-0.%d", | ||
| 1147 | CPU, bfin_compiled_revid()); | ||
| 1148 | |||
| 1149 | if (bfin_compiled_revid() != bfin_revid()) | ||
| 1150 | verbose_printk("(Detected 0.%d)", bfin_revid()); | ||
| 1151 | |||
| 1152 | verbose_printk(" %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n", | ||
| 1153 | get_cclk()/1000000, get_sclk()/1000000, | ||
| 1154 | #ifdef CONFIG_MPU | ||
| 1155 | "mpu on" | ||
| 1156 | #else | ||
| 1157 | "mpu off" | ||
| 1158 | #endif | ||
| 1159 | ); | ||
| 1160 | |||
| 1161 | verbose_printk(KERN_NOTICE "%s", linux_banner); | ||
| 1162 | |||
| 1163 | verbose_printk(KERN_NOTICE "\nSEQUENCER STATUS:\t\t%s\n", print_tainted()); | ||
| 1164 | verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx IMASK: %04lx SYSCFG: %04lx\n", | ||
| 1165 | (long)fp->seqstat, fp->ipend, cpu_pda[raw_smp_processor_id()].ex_imask, fp->syscfg); | ||
| 1166 | if (fp->ipend & EVT_IRPTEN) | ||
| 1167 | verbose_printk(KERN_NOTICE " Global Interrupts Disabled (IPEND[4])\n"); | ||
| 1168 | if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG13 | EVT_IVG12 | EVT_IVG11 | | ||
| 1169 | EVT_IVG10 | EVT_IVG9 | EVT_IVG8 | EVT_IVG7 | EVT_IVTMR))) | ||
| 1170 | verbose_printk(KERN_NOTICE " Peripheral interrupts masked off\n"); | ||
| 1171 | if (!(cpu_pda[raw_smp_processor_id()].ex_imask & (EVT_IVG15 | EVT_IVG14))) | ||
| 1172 | verbose_printk(KERN_NOTICE " Kernel interrupts masked off\n"); | ||
| 1173 | if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) { | ||
| 1174 | verbose_printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n", | ||
| 1175 | (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14); | ||
| 1176 | #ifdef EBIU_ERRMST | ||
| 1177 | /* If the error was from the EBIU, print it out */ | ||
| 1178 | if (bfin_read_EBIU_ERRMST() & CORE_ERROR) { | ||
| 1179 | verbose_printk(KERN_NOTICE " EBIU Error Reason : 0x%04x\n", | ||
| 1180 | bfin_read_EBIU_ERRMST()); | ||
| 1181 | verbose_printk(KERN_NOTICE " EBIU Error Address : 0x%08x\n", | ||
| 1182 | bfin_read_EBIU_ERRADD()); | ||
| 1183 | } | ||
| 1184 | #endif | 526 | #endif |
| 527 | { | ||
| 528 | dump_bfin_process(fp); | ||
| 529 | dump_bfin_mem(fp); | ||
| 530 | show_regs(fp); | ||
| 531 | dump_bfin_trace_buffer(); | ||
| 1185 | } | 532 | } |
| 1186 | verbose_printk(KERN_NOTICE " EXCAUSE : 0x%lx\n", | ||
| 1187 | fp->seqstat & SEQSTAT_EXCAUSE); | ||
| 1188 | for (i = 2; i <= 15 ; i++) { | ||
| 1189 | if (fp->ipend & (1 << i)) { | ||
| 1190 | if (i != 4) { | ||
| 1191 | decode_address(buf, bfin_read32(EVT0 + 4*i)); | ||
| 1192 | verbose_printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf); | ||
| 1193 | } else | ||
| 1194 | verbose_printk(KERN_NOTICE " interrupts disabled\n"); | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | /* if no interrupts are going off, don't print this out */ | ||
| 1199 | if (fp->ipend & ~0x3F) { | ||
| 1200 | for (i = 0; i < (NR_IRQS - 1); i++) { | ||
| 1201 | if (!in_atomic) | ||
| 1202 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
| 1203 | |||
| 1204 | action = irq_desc[i].action; | ||
| 1205 | if (!action) | ||
| 1206 | goto unlock; | ||
| 1207 | |||
| 1208 | decode_address(buf, (unsigned int)action->handler); | ||
| 1209 | verbose_printk(KERN_NOTICE " logical irq %3d mapped : %s", i, buf); | ||
| 1210 | for (action = action->next; action; action = action->next) { | ||
| 1211 | decode_address(buf, (unsigned int)action->handler); | ||
| 1212 | verbose_printk(", %s", buf); | ||
| 1213 | } | ||
| 1214 | verbose_printk("\n"); | ||
| 1215 | unlock: | ||
| 1216 | if (!in_atomic) | ||
| 1217 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
| 1218 | } | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | decode_address(buf, fp->rete); | ||
| 1222 | verbose_printk(KERN_NOTICE " RETE: %s\n", buf); | ||
| 1223 | decode_address(buf, fp->retn); | ||
| 1224 | verbose_printk(KERN_NOTICE " RETN: %s\n", buf); | ||
| 1225 | decode_address(buf, fp->retx); | ||
| 1226 | verbose_printk(KERN_NOTICE " RETX: %s\n", buf); | ||
| 1227 | decode_address(buf, fp->rets); | ||
| 1228 | verbose_printk(KERN_NOTICE " RETS: %s\n", buf); | ||
| 1229 | decode_address(buf, fp->pc); | ||
| 1230 | verbose_printk(KERN_NOTICE " PC : %s\n", buf); | ||
| 1231 | |||
| 1232 | if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && | ||
| 1233 | (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { | ||
| 1234 | decode_address(buf, cpu_pda[cpu].dcplb_fault_addr); | ||
| 1235 | verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); | ||
| 1236 | decode_address(buf, cpu_pda[cpu].icplb_fault_addr); | ||
| 1237 | verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | verbose_printk(KERN_NOTICE "PROCESSOR STATE:\n"); | ||
| 1241 | verbose_printk(KERN_NOTICE " R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", | ||
| 1242 | fp->r0, fp->r1, fp->r2, fp->r3); | ||
| 1243 | verbose_printk(KERN_NOTICE " R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", | ||
| 1244 | fp->r4, fp->r5, fp->r6, fp->r7); | ||
| 1245 | verbose_printk(KERN_NOTICE " P0 : %08lx P1 : %08lx P2 : %08lx P3 : %08lx\n", | ||
| 1246 | fp->p0, fp->p1, fp->p2, fp->p3); | ||
| 1247 | verbose_printk(KERN_NOTICE " P4 : %08lx P5 : %08lx FP : %08lx SP : %08lx\n", | ||
| 1248 | fp->p4, fp->p5, fp->fp, (long)fp); | ||
| 1249 | verbose_printk(KERN_NOTICE " LB0: %08lx LT0: %08lx LC0: %08lx\n", | ||
| 1250 | fp->lb0, fp->lt0, fp->lc0); | ||
| 1251 | verbose_printk(KERN_NOTICE " LB1: %08lx LT1: %08lx LC1: %08lx\n", | ||
| 1252 | fp->lb1, fp->lt1, fp->lc1); | ||
| 1253 | verbose_printk(KERN_NOTICE " B0 : %08lx L0 : %08lx M0 : %08lx I0 : %08lx\n", | ||
| 1254 | fp->b0, fp->l0, fp->m0, fp->i0); | ||
| 1255 | verbose_printk(KERN_NOTICE " B1 : %08lx L1 : %08lx M1 : %08lx I1 : %08lx\n", | ||
| 1256 | fp->b1, fp->l1, fp->m1, fp->i1); | ||
| 1257 | verbose_printk(KERN_NOTICE " B2 : %08lx L2 : %08lx M2 : %08lx I2 : %08lx\n", | ||
| 1258 | fp->b2, fp->l2, fp->m2, fp->i2); | ||
| 1259 | verbose_printk(KERN_NOTICE " B3 : %08lx L3 : %08lx M3 : %08lx I3 : %08lx\n", | ||
| 1260 | fp->b3, fp->l3, fp->m3, fp->i3); | ||
| 1261 | verbose_printk(KERN_NOTICE "A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", | ||
| 1262 | fp->a0w, fp->a0x, fp->a1w, fp->a1x); | ||
| 1263 | |||
| 1264 | verbose_printk(KERN_NOTICE "USP : %08lx ASTAT: %08lx\n", | ||
| 1265 | rdusp(), fp->astat); | ||
| 1266 | |||
| 1267 | verbose_printk(KERN_NOTICE "\n"); | ||
| 1268 | #endif | 533 | #endif |
| 1269 | } | 534 | panic("Double Fault - unrecoverable event"); |
| 1270 | |||
| 1271 | #ifdef CONFIG_SYS_BFIN_SPINLOCK_L1 | ||
| 1272 | asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text)); | ||
| 1273 | #endif | ||
| 1274 | |||
| 1275 | static DEFINE_SPINLOCK(bfin_spinlock_lock); | ||
| 1276 | |||
| 1277 | asmlinkage int sys_bfin_spinlock(int *p) | ||
| 1278 | { | ||
| 1279 | int ret, tmp = 0; | ||
| 1280 | |||
| 1281 | spin_lock(&bfin_spinlock_lock); /* This would also hold kernel preemption. */ | ||
| 1282 | ret = get_user(tmp, p); | ||
| 1283 | if (likely(ret == 0)) { | ||
| 1284 | if (unlikely(tmp)) | ||
| 1285 | ret = 1; | ||
| 1286 | else | ||
| 1287 | put_user(1, p); | ||
| 1288 | } | ||
| 1289 | spin_unlock(&bfin_spinlock_lock); | ||
| 1290 | return ret; | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | int bfin_request_exception(unsigned int exception, void (*handler)(void)) | ||
| 1294 | { | ||
| 1295 | void (*curr_handler)(void); | ||
| 1296 | |||
| 1297 | if (exception > 0x3F) | ||
| 1298 | return -EINVAL; | ||
| 1299 | |||
| 1300 | curr_handler = ex_table[exception]; | ||
| 1301 | |||
| 1302 | if (curr_handler != ex_replaceable) | ||
| 1303 | return -EBUSY; | ||
| 1304 | |||
| 1305 | ex_table[exception] = handler; | ||
| 1306 | 535 | ||
| 1307 | return 0; | ||
| 1308 | } | 536 | } |
| 1309 | EXPORT_SYMBOL(bfin_request_exception); | ||
| 1310 | |||
| 1311 | int bfin_free_exception(unsigned int exception, void (*handler)(void)) | ||
| 1312 | { | ||
| 1313 | void (*curr_handler)(void); | ||
| 1314 | |||
| 1315 | if (exception > 0x3F) | ||
| 1316 | return -EINVAL; | ||
| 1317 | |||
| 1318 | curr_handler = ex_table[exception]; | ||
| 1319 | 537 | ||
| 1320 | if (curr_handler != handler) | ||
| 1321 | return -EBUSY; | ||
| 1322 | |||
| 1323 | ex_table[exception] = ex_replaceable; | ||
| 1324 | |||
| 1325 | return 0; | ||
| 1326 | } | ||
| 1327 | EXPORT_SYMBOL(bfin_free_exception); | ||
| 1328 | 538 | ||
| 1329 | void panic_cplb_error(int cplb_panic, struct pt_regs *fp) | 539 | void panic_cplb_error(int cplb_panic, struct pt_regs *fp) |
| 1330 | { | 540 | { |
| @@ -1349,3 +559,23 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp) | |||
| 1349 | dump_stack(); | 559 | dump_stack(); |
| 1350 | panic("Unrecoverable event"); | 560 | panic("Unrecoverable event"); |
| 1351 | } | 561 | } |
| 562 | |||
| 563 | #ifdef CONFIG_BUG | ||
| 564 | int is_valid_bugaddr(unsigned long addr) | ||
| 565 | { | ||
| 566 | unsigned int opcode; | ||
| 567 | |||
| 568 | if (!get_instruction(&opcode, (unsigned short *)addr)) | ||
| 569 | return 0; | ||
| 570 | |||
| 571 | return opcode == BFIN_BUG_OPCODE; | ||
| 572 | } | ||
| 573 | #endif | ||
| 574 | |||
| 575 | /* stub this out */ | ||
| 576 | #ifndef CONFIG_DEBUG_VERBOSE | ||
| 577 | void show_regs(struct pt_regs *fp) | ||
| 578 | { | ||
| 579 | |||
| 580 | } | ||
| 581 | #endif | ||
