From f4585a08479a730fb809606b8ee327a5398c117c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 13 Oct 2008 14:45:21 +0800 Subject: Blackfin arch: only include asm/cplb.h when it is truly used Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 9a9d5083acfd..fd24e04fc19e 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-58-ga151 From 0c7a6b2135c1bcb5139ca9ca87f292caafcb9410 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 8 Oct 2008 16:27:12 +0800 Subject: Blackfin arch: add supporting for double fault debug handling Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig.debug | 38 ++++++++ arch/blackfin/kernel/setup.c | 30 ++++-- arch/blackfin/kernel/traps.c | 34 ++++++- arch/blackfin/mach-common/entry.S | 189 ++++++++++++++++++++++++++------------ arch/blackfin/mach-common/head.S | 40 +++++++- 5 files changed, 255 insertions(+), 76 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index c468624d55f0..0afa89818722 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -22,6 +22,44 @@ config DEBUG_HWERR hardware error interrupts and need to know where they are coming from. +config DEBUG_DOUBLEFAULT + bool "Debug Double Faults" + default n + help + If an exception is caused while executing code within the exception + handler, the NMI handler, the reset vector, or in emulator mode, + a double fault occurs. On the Blackfin, this is a unrecoverable + event. You have two options: + - RESET exactly when double fault occurs. The excepting + instruction address is stored in RETX, where the next kernel + boot will print it out. + - Print debug message. This is much more error prone, although + easier to handle. It is error prone since: + - The excepting instruction is not committed. + - All writebacks from the instruction are prevented. + - The generated exception is not taken. + - The EXCAUSE field is updated with an unrecoverable event + The only way to check this is to see if EXCAUSE contains the + unrecoverable event value at every exception return. By selecting + this option, you are skipping over the faulting instruction, and + hoping things stay together enough to print out a debug message. + + This does add a little kernel code, but is the only method to debug + double faults - if unsure say "Y" + +choice + prompt "Double Fault Failure Method" + default DEBUG_DOUBLEFAULT_PRINT + depends on DEBUG_DOUBLEFAULT + +config DEBUG_DOUBLEFAULT_PRINT + bool "Print" + +config DEBUG_DOUBLEFAULT_RESET + bool "Reset" + +endchoice + config DEBUG_ICACHE_CHECK bool "Check Instruction cache coherency" depends on DEBUG_KERNEL diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 7a82d10b4ebf..8e639dc886a3 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -52,7 +52,8 @@ EXPORT_SYMBOL(mtd_size); #endif char __initdata command_line[COMMAND_LINE_SIZE]; -unsigned int __initdata *__retx; +void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat, + *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr; /* boot memmap, for parsing "memmap=" */ #define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */ @@ -782,16 +783,25 @@ void __init setup_arch(char **cmdline_p) _bfin_swrst = bfin_read_SWRST(); - /* If we double fault, reset the system - otherwise we hang forever */ - bfin_write_SWRST(DOUBLE_FAULT); +#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT + bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT); +#endif +#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET + bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT); +#endif - if (_bfin_swrst & RESET_DOUBLE) - /* - * don't decode the address, since you don't know if this - * kernel's symbol map is the same as the crashing kernel - */ - printk(KERN_INFO "Recovering from Double Fault event at %pF\n", __retx); - else if (_bfin_swrst & RESET_WDOG) + if (_bfin_swrst & RESET_DOUBLE) { + printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n"); +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* We assume the crashing kernel, and the current symbol table match */ + printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", + (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr); +#endif + printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", + init_retx); + } else if (_bfin_swrst & RESET_WDOG) printk(KERN_INFO "Recovering from Watchdog event\n"); else if (_bfin_swrst & RESET_SOFTWARE) printk(KERN_NOTICE "Reset caused by Software reset\n"); diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index fd24e04fc19e..bd41fca315dd 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -68,7 +68,15 @@ void __init trap_init(void) CSYNC(); } -unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr; +/* + * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR + * values across the transition from exception to IRQ5. + * We put these in L1, so they are going to be in a valid + * location during exception context + */ +__attribute__((l1_data)) +unsigned long saved_retx, saved_seqstat, + saved_icplb_fault_addr, saved_dcplb_fault_addr; static void decode_address(char *buf, unsigned long address) { @@ -186,9 +194,27 @@ asmlinkage void double_fault_c(struct pt_regs *fp) console_verbose(); oops_in_progress = 1; printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); - dump_bfin_process(fp); - dump_bfin_mem(fp); - show_regs(fp); +#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT + if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { + char buf[150]; + decode_address(buf, saved_retx); + printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", + (int)saved_seqstat & SEQSTAT_EXCAUSE, buf); + decode_address(buf, saved_dcplb_fault_addr); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); + decode_address(buf, saved_icplb_fault_addr); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); + + decode_address(buf, fp->retx); + printk(KERN_NOTICE "The instruction at %s caused a double exception\n", + buf); + } else +#endif + { + dump_bfin_process(fp); + dump_bfin_mem(fp); + show_regs(fp); + } panic("Double Fault - unrecoverable event\n"); } diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 847c172a99eb..90c7397036ed 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -129,6 +129,18 @@ ENTRY(_ex_icplb_miss) #else call __cplb_hdr; #endif + +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* While we were processing this, did we double fault? */ + r7 = SEQSTAT; /* reason code is in bit 5:0 */ + r6.l = lo(SEQSTAT_EXCAUSE); + r6.h = hi(SEQSTAT_EXCAUSE); + r7 = r7 & r6; + r6 = 0x25; + CC = R7 == R6; + if CC JUMP _double_fault; +#endif + DEBUG_HWTRACE_RESTORE(p5, r7) RESTORE_ALL_SYS SP = EX_SCRATCH_REG; @@ -136,11 +148,8 @@ ENTRY(_ex_icplb_miss) ENDPROC(_ex_icplb_miss) ENTRY(_ex_syscall) - (R7:6,P5:4) = [sp++]; - ASTAT = [sp++]; raise 15; /* invoked by TRAP #0, for sys call */ - sp = EX_SCRATCH_REG; - rtx + jump.s _bfin_return_from_exception; ENDPROC(_ex_syscall) ENTRY(_ex_soft_bp) @@ -250,6 +259,29 @@ ENTRY(_bfin_return_from_exception) R7=LC1; LC1=R7; #endif + +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* While we were processing the current exception, + * did we cause another, and double fault? + */ + r7 = SEQSTAT; /* reason code is in bit 5:0 */ + r6.l = lo(SEQSTAT_EXCAUSE); + r6.h = hi(SEQSTAT_EXCAUSE); + r7 = r7 & r6; + r6 = 0x25; + CC = R7 == R6; + if CC JUMP _double_fault; + + /* Did we cause a HW error? */ + p5.l = lo(ILAT); + p5.h = hi(ILAT); + r6 = [p5]; + r7 = 0x20; /* Did I just cause anther HW error? */ + r7 = r7 & r1; + CC = R7 == R6; + if CC JUMP _double_fault; +#endif + (R7:6,P5:4) = [sp++]; ASTAT = [sp++]; sp = EX_SCRATCH_REG; @@ -292,6 +324,14 @@ ENTRY(_ex_trap_c) [p4] = p5; csync; +#ifndef CONFIG_DEBUG_DOUBLEFAULT + /* + * Save these registers, as they are only valid in exception context + * (where we are now - as soon as we defer to IRQ5, they can change) + * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3, + * but they are not very interesting, so don't save them + */ + p4.l = lo(DCPLB_FAULT_ADDR); p4.h = hi(DCPLB_FAULT_ADDR); r7 = [p4]; @@ -304,12 +344,11 @@ ENTRY(_ex_trap_c) p5.l = _saved_icplb_fault_addr; [p5] = r7; - p4.l = _excpt_saved_stuff; - p4.h = _excpt_saved_stuff; - r6 = retx; + p4.l = _saved_retx; + p4.h = _saved_retx; [p4] = r6; - +#endif r6 = SYSCFG; [p4 + 4] = r6; BITCLR(r6, 0); @@ -327,59 +366,56 @@ ENTRY(_ex_trap_c) r6 = 0x3f; sti r6; - (R7:6,P5:4) = [sp++]; - ASTAT = [sp++]; - SP = EX_SCRATCH_REG; raise 5; - rtx; + jump.s _bfin_return_from_exception; ENDPROC(_ex_trap_c) /* We just realized we got an exception, while we were processing a different * exception. This is a unrecoverable event, so crash */ ENTRY(_double_fault) - /* Turn caches & protection off, to ensure we don't get any more - * double exceptions - */ - - P4.L = LO(IMEM_CONTROL); - P4.H = HI(IMEM_CONTROL); - - R5 = [P4]; /* Control Register*/ - BITCLR(R5,ENICPLB_P); - SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ - .align 8; - [P4] = R5; - SSYNC; - - P4.L = LO(DMEM_CONTROL); - P4.H = HI(DMEM_CONTROL); - R5 = [P4]; - BITCLR(R5,ENDCPLB_P); - SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ - .align 8; - [P4] = R5; - SSYNC; - - /* Fix up the stack */ - (R7:6,P5:4) = [sp++]; - ASTAT = [sp++]; - SP = EX_SCRATCH_REG; - - /* We should be out of the exception stack, and back down into - * kernel or user space stack - */ - SAVE_ALL_SYS + /* Turn caches & protection off, to ensure we don't get any more + * double exceptions + */ + + P4.L = LO(IMEM_CONTROL); + P4.H = HI(IMEM_CONTROL); + + R5 = [P4]; /* Control Register*/ + BITCLR(R5,ENICPLB_P); + SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + + P4.L = LO(DMEM_CONTROL); + P4.H = HI(DMEM_CONTROL); + R5 = [P4]; + BITCLR(R5,ENDCPLB_P); + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P4] = R5; + SSYNC; + + /* Fix up the stack */ + (R7:6,P5:4) = [sp++]; + ASTAT = [sp++]; + SP = EX_SCRATCH_REG; + + /* We should be out of the exception stack, and back down into + * kernel or user space stack + */ + SAVE_ALL_SYS /* The dumping functions expect the return address in the RETI * slot. */ r6 = retx; [sp + PT_PC] = r6; - r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ - SP += -12; - call _double_fault_c; - SP += 12; + r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ + SP += -12; + call _double_fault_c; + SP += 12; .L_double_fault_panic: JUMP .L_double_fault_panic @@ -388,8 +424,8 @@ ENDPROC(_double_fault) ENTRY(_exception_to_level5) SAVE_ALL_SYS - p4.l = _excpt_saved_stuff; - p4.h = _excpt_saved_stuff; + p4.l = _saved_retx; + p4.h = _saved_retx; r6 = [p4]; [sp + PT_PC] = r6; @@ -420,6 +456,17 @@ ENTRY(_exception_to_level5) call _trap_c; SP += 12; +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* Grab ILAT */ + p2.l = lo(ILAT); + p2.h = hi(ILAT); + r0 = [p2]; + r1 = 0x20; /* Did I just cause anther HW error? */ + r0 = r0 & r1; + CC = R0 == R1; + if CC JUMP _double_fault; +#endif + call _ret_from_exception; RESTORE_ALL_SYS rti; @@ -436,7 +483,39 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ /* Try to deal with syscalls quickly. */ [--sp] = ASTAT; [--sp] = (R7:6,P5:4); + +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* + * Save these registers, as they are only valid in exception context + * (where we are now - as soon as we defer to IRQ5, they can change) + * DCPLB_STATUS and ICPLB_STATUS are also only valid in EVT3, + * but they are not very interesting, so don't save them + */ + + p4.l = lo(DCPLB_FAULT_ADDR); + p4.h = hi(DCPLB_FAULT_ADDR); + r7 = [p4]; + p5.h = _saved_dcplb_fault_addr; + p5.l = _saved_dcplb_fault_addr; + [p5] = r7; + + r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; + p5.h = _saved_icplb_fault_addr; + p5.l = _saved_icplb_fault_addr; + [p5] = r7; + + p4.l = _saved_retx; + p4.h = _saved_retx; + r6 = retx; + [p4] = r6; + r7 = SEQSTAT; /* reason code is in bit 5:0 */ + p4.l = _saved_seqstat; + p4.h = _saved_seqstat; + [p4] = r7; +#else + r7 = SEQSTAT; /* reason code is in bit 5:0 */ +#endif r6.l = lo(SEQSTAT_EXCAUSE); r6.h = hi(SEQSTAT_EXCAUSE); r7 = r7 & r6; @@ -1432,15 +1511,7 @@ ENTRY(_sys_call_table) .rept NR_syscalls-(.-_sys_call_table)/4 .long _sys_ni_syscall .endr - - /* - * Used to save the real RETX, IMASK and SYSCFG when temporarily - * storing safe values across the transition from exception to IRQ5. - */ -_excpt_saved_stuff: - .long 0; - .long 0; - .long 0; +END(_sys_call_table) _exception_stack: .rept 1024 diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index 191b4e974c4b..7cb21cfcbf28 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -90,12 +90,46 @@ ENTRY(__start) [p0] = R0; SSYNC; - /* Save RETX, in case of doublefault */ - p0.l = ___retx; - p0.h = ___retx; + /* in case of double faults, save a few things */ + p0.l = _init_retx; + p0.h = _init_retx; R0 = RETX; [P0] = R0; +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* Only save these if we are storing them, + * This happens here, since L1 gets clobbered + * below + */ + p0.l = _saved_retx; + p0.h = _saved_retx; + p1.l = _init_saved_retx; + p1.h = _init_saved_retx; + r0 = [p0]; + [p1] = r0; + + p0.l = _saved_dcplb_fault_addr; + p0.h = _saved_dcplb_fault_addr; + p1.l = _init_saved_dcplb_fault_addr; + p1.h = _init_saved_dcplb_fault_addr; + r0 = [p0]; + [p1] = r0; + + p0.l = _saved_icplb_fault_addr; + p0.h = _saved_icplb_fault_addr; + p1.l = _init_saved_icplb_fault_addr; + p1.h = _init_saved_icplb_fault_addr; + r0 = [p0]; + [p1] = r0; + + p0.l = _saved_seqstat; + p0.h = _saved_seqstat; + p1.l = _init_saved_seqstat; + p1.h = _init_saved_seqstat; + r0 = [p0]; + [p1] = r0; +#endif + /* Initialize stack pointer */ sp.l = lo(INITIAL_STACK); sp.h = hi(INITIAL_STACK); -- cgit v1.2.3-58-ga151 From 5d2e321306f82550e6d354b3210a18b86bdb13c1 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Tue, 7 Oct 2008 16:27:01 +0800 Subject: Blackfin arch: fixing bug - under IRQ stress, running applications may wrongly trigger an ICPLB miss and be killed Disable IRQs while frobbing the CPLB registers, to avoid accessing the data in current_rwx_mask while it isn't covered by CPLBs. Signed-off-by: Bernd Schmidt Signed-off-by: Bryan Wu --- arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index 99f2831e2964..5094677fd09e 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -322,9 +322,11 @@ int cplb_hdr(int seqstat, struct pt_regs *regs) void flush_switched_cplbs(void) { int i; + unsigned long flags; nr_cplb_flush++; + local_irq_save(flags); disable_icplb(); for (i = first_switched_icplb; i < MAX_CPLBS; i++) { icplb_tbl[i].data = 0; @@ -338,6 +340,8 @@ void flush_switched_cplbs(void) bfin_write32(DCPLB_DATA0 + i * 4, 0); } enable_dcplb(); + local_irq_restore(flags); + } void set_mask_dcplbs(unsigned long *masks) @@ -345,10 +349,15 @@ void set_mask_dcplbs(unsigned long *masks) int i; unsigned long addr = (unsigned long)masks; unsigned long d_data; - current_rwx_mask = masks; + unsigned long flags; - if (!masks) + if (!masks) { + current_rwx_mask = masks; return; + } + + local_irq_save(flags); + current_rwx_mask = masks; d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; #ifdef CONFIG_BFIN_DCACHE @@ -367,4 +376,5 @@ void set_mask_dcplbs(unsigned long *masks) addr += PAGE_SIZE; } enable_dcplb(); + local_irq_restore(flags); } -- cgit v1.2.3-58-ga151 From a5ac0129249611fc4a35e6d7cd9b8462d67e5798 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Mon, 13 Oct 2008 14:07:19 +0800 Subject: Blackfin arch: add supporting for kgdb Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- Documentation/blackfin/kgdb.txt | 155 ------ arch/blackfin/Kconfig.debug | 3 + arch/blackfin/include/asm/kgdb.h | 21 +- arch/blackfin/kernel/kgdb.c | 711 ++++++++++++++++++------ arch/blackfin/kernel/traps.c | 35 +- arch/blackfin/mach-bf561/include/mach/mem_map.h | 18 +- arch/blackfin/mach-common/entry.S | 9 +- arch/blackfin/mach-common/ints-priority.c | 4 - 8 files changed, 606 insertions(+), 350 deletions(-) delete mode 100644 Documentation/blackfin/kgdb.txt (limited to 'arch/blackfin/kernel') diff --git a/Documentation/blackfin/kgdb.txt b/Documentation/blackfin/kgdb.txt deleted file mode 100644 index 84f6a484ae9a..000000000000 --- a/Documentation/blackfin/kgdb.txt +++ /dev/null @@ -1,155 +0,0 @@ - A Simple Guide to Configure KGDB - - Sonic Zhang - Aug. 24th 2006 - - -This KGDB patch enables the kernel developer to do source level debugging on -the kernel for the Blackfin architecture. The debugging works over either the -ethernet interface or one of the uarts. Both software breakpoints and -hardware breakpoints are supported in this version. -http://docs.blackfin.uclinux.org/doku.php?id=kgdb - - -2 known issues: -1. This bug: - http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145 - The GDB client for Blackfin uClinux causes incorrect values of local - variables to be displayed when the user breaks the running of kernel in GDB. -2. Because of a hardware bug in Blackfin 533 v1.0.3: - 05000067 - Watchpoints (Hardware Breakpoints) are not supported - Hardware breakpoints cannot be set properly. - - -Debug over Ethernet: - -1. Compile and install the cross platform version of gdb for blackfin, which - can be found at $(BINROOT)/bfin-elf-gdb. - -2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under - "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb". - With this selected, option "Full Symbolic/Source Debugging support" and - "Compile the kernel with frame pointers" are also selected. - -3. Select option "KGDB: connect over (Ethernet)". Add "kgdboe=@target-IP/,@host-IP/" to - the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking". - -4. Connect minicom to the serial port and boot the kernel image. - -5. Configure the IP "/> ifconfig eth0 target-IP" - -6. Start GDB client "bfin-elf-gdb vmlinux". - -7. Connect to the target "(gdb) target remote udp:target-IP:6443". - -8. Set software breakpoint "(gdb) break sys_open". - -9. Continue "(gdb) c". - -10. Run ls in the target console "/> ls". - -11. Breakpoint hits. "Breakpoint 1: sys_open(..." - -12. Display local variables and function paramters. - (*) This operation gives wrong results, see known issue 1. - -13. Single stepping "(gdb) si". - -14. Remove breakpoint 1. "(gdb) del 1" - -15. Set hardware breakpoint "(gdb) hbreak sys_open". - -16. Continue "(gdb) c". - -17. Run ls in the target console "/> ls". - -18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...". - (*) This hardware breakpoint will not be hit, see known issue 2. - -19. Continue "(gdb) c". - -20. Interrupt the target in GDB "Ctrl+C". - -21. Detach from the target "(gdb) detach". - -22. Exit GDB "(gdb) quit". - - -Debug over the UART: - -1. Compile and install the cross platform version of gdb for blackfin, which - can be found at $(BINROOT)/bfin-elf-gdb. - -2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under - "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb". - With this selected, option "Full Symbolic/Source Debugging support" and - "Compile the kernel with frame pointers" are also selected. - -3. Select option "KGDB: connect over (UART)". Set "KGDB: UART port number" to be - a different one from the console. Don't forget to change the mode of - blackfin serial driver to PIO. Otherwise kgdb works incorrectly on UART. - -4. If you want connect to kgdb when the kernel boots, enable - "KGDB: Wait for gdb connection early" - -5. Compile kernel. - -6. Connect minicom to the serial port of the console and boot the kernel image. - -7. Start GDB client "bfin-elf-gdb vmlinux". - -8. Set the baud rate in GDB "(gdb) set remotebaud 57600". - -9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1". - -10. Set software breakpoint "(gdb) break sys_open". - -11. Continue "(gdb) c". - -12. Run ls in the target console "/> ls". - -13. A breakpoint is hit. "Breakpoint 1: sys_open(..." - -14. All other operations are the same as that in KGDB over Ethernet. - - -Debug over the same UART as console: - -1. Compile and install the cross platform version of gdb for blackfin, which - can be found at $(BINROOT)/bfin-elf-gdb. - -2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under - "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb". - With this selected, option "Full Symbolic/Source Debugging support" and - "Compile the kernel with frame pointers" are also selected. - -3. Select option "KGDB: connect over UART". Set "KGDB: UART port number" to console. - Don't forget to change the mode of blackfin serial driver to PIO. - Otherwise kgdb works incorrectly on UART. - -4. If you want connect to kgdb when the kernel boots, enable - "KGDB: Wait for gdb connection early" - -5. Connect minicom to the serial port and boot the kernel image. - -6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A. - -7. Start GDB client "bfin-elf-gdb vmlinux". - -8. Set the baud rate in GDB "(gdb) set remotebaud 57600". - -9. Connect to the target "(gdb) target remote /dev/ttyS0". - -10. Set software breakpoint "(gdb) break sys_open". - -11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection. - -12. Run ls in the target console "/> ls". Dummy string can be seen on the console. - -13. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0". - Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..." - -14. All other operations are the same as that in KGDB over Ethernet. The only - difference is that after continue command in GDB, please stop GDB - connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or - Ctrl+A is entered. diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index 0afa89818722..2cb0a3080d79 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -2,6 +2,9 @@ menu "Kernel hacking" source "lib/Kconfig.debug" +config HAVE_ARCH_KGDB + def_bool y + config DEBUG_MMRS bool "Generate Blackfin MMR tree" select DEBUG_FS diff --git a/arch/blackfin/include/asm/kgdb.h b/arch/blackfin/include/asm/kgdb.h index 0f73847fd6bc..26ebac6646d8 100644 --- a/arch/blackfin/include/asm/kgdb.h +++ b/arch/blackfin/include/asm/kgdb.h @@ -124,9 +124,16 @@ enum regnames { /* Number of bytes of registers. */ #define NUMREGBYTES BFIN_NUM_REGS*4 -#define BREAKPOINT() asm(" EXCPT 2;"); -#define BREAK_INSTR_SIZE 2 -#define HW_BREAKPOINT_NUM 6 +static inline void arch_kgdb_breakpoint(void) +{ + asm(" EXCPT 2;"); +} +#define BREAK_INSTR_SIZE 2 +#define CACHE_FLUSH_IS_SAFE 1 +#define HW_INST_WATCHPOINT_NUM 6 +#define HW_WATCHPOINT_NUM 8 +#define TYPE_INST_WATCHPOINT 0 +#define TYPE_DATA_WATCHPOINT 1 /* Instruction watchpoint address control register bits mask */ #define WPPWR 0x1 @@ -163,10 +170,11 @@ enum regnames { #define WPDAEN1 0x8 #define WPDCNTEN0 0x10 #define WPDCNTEN1 0x20 + #define WPDSRC0 0xc0 -#define WPDACC0 0x300 +#define WPDACC0_OFFSET 8 #define WPDSRC1 0xc00 -#define WPDACC1 0x3000 +#define WPDACC1_OFFSET 12 /* Watchpoint status register bits mask */ #define STATIA0 0x1 @@ -178,7 +186,4 @@ enum regnames { #define STATDA0 0x40 #define STATDA1 0x80 -extern void kgdb_print(const char *fmt, ...); -extern void init_kgdb_uart(void); - #endif diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index a1f9641a6425..b795a207742c 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c @@ -1,32 +1,9 @@ /* - * File: arch/blackfin/kernel/kgdb.c - * Based on: - * Author: Sonic Zhang + * arch/blackfin/kernel/kgdb.c - Blackfin kgdb pieces * - * Created: - * Description: + * Copyright 2005-2008 Analog Devices Inc. * - * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $ - * - * Modified: - * Copyright 2005-2006 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Licensed under the GPL-2 or later. */ #include @@ -39,24 +16,29 @@ #include #include #include -#include #include #include +#include #include #include #include +#include /* Put the error code here just in case the user cares. */ -int gdb_bf533errcode; +int gdb_bfin_errcode; /* Likewise, the vector number here (since GDB only gets the signal number through the usual means, and that's not very specific). */ -int gdb_bf533vector = -1; +int gdb_bfin_vector = -1; #if KGDB_MAX_NO_CPUS != 8 #error change the definition of slavecpulocks #endif -void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +#ifdef CONFIG_BFIN_WDT +# error "Please unselect blackfin watchdog driver before build KGDB." +#endif + +void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) { gdb_regs[BFIN_R0] = regs->r0; gdb_regs[BFIN_R1] = regs->r1; @@ -133,7 +115,7 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat; } -void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) { regs->r0 = gdb_regs[BFIN_R0]; regs->r1 = gdb_regs[BFIN_R1]; @@ -199,171 +181,208 @@ struct hw_breakpoint { unsigned int dataacc:2; unsigned short count; unsigned int addr; -} breakinfo[HW_BREAKPOINT_NUM]; +} breakinfo[HW_WATCHPOINT_NUM]; -int kgdb_arch_init(void) -{ - debugger_step = 0; - - kgdb_remove_all_hw_break(); - return 0; -} - -int kgdb_set_hw_break(unsigned long addr) +int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type) { int breakno; - for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) - if (!breakinfo[breakno].occupied) { + int bfin_type; + int dataacc = 0; + + switch (type) { + case BP_HARDWARE_BREAKPOINT: + bfin_type = TYPE_INST_WATCHPOINT; + break; + case BP_WRITE_WATCHPOINT: + dataacc = 1; + bfin_type = TYPE_DATA_WATCHPOINT; + break; + case BP_READ_WATCHPOINT: + dataacc = 2; + bfin_type = TYPE_DATA_WATCHPOINT; + break; + case BP_ACCESS_WATCHPOINT: + dataacc = 3; + bfin_type = TYPE_DATA_WATCHPOINT; + break; + default: + return -ENOSPC; + } + + /* Becasue hardware data watchpoint impelemented in current + * Blackfin can not trigger an exception event as the hardware + * instrction watchpoint does, we ignaore all data watch point here. + * They can be turned on easily after future blackfin design + * supports this feature. + */ + for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++) + if (bfin_type == breakinfo[breakno].type + && !breakinfo[breakno].occupied) { breakinfo[breakno].occupied = 1; breakinfo[breakno].enabled = 1; - breakinfo[breakno].type = 1; breakinfo[breakno].addr = addr; + breakinfo[breakno].dataacc = dataacc; + breakinfo[breakno].count = 0; return 0; } return -ENOSPC; } -int kgdb_remove_hw_break(unsigned long addr) +int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type) { int breakno; - for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) - if (breakinfo[breakno].addr == addr) - memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint)); + int bfin_type; + + switch (type) { + case BP_HARDWARE_BREAKPOINT: + bfin_type = TYPE_INST_WATCHPOINT; + break; + case BP_WRITE_WATCHPOINT: + case BP_READ_WATCHPOINT: + case BP_ACCESS_WATCHPOINT: + bfin_type = TYPE_DATA_WATCHPOINT; + break; + default: + return 0; + } + for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) + if (bfin_type == breakinfo[breakno].type + && breakinfo[breakno].occupied + && breakinfo[breakno].addr == addr) { + breakinfo[breakno].occupied = 0; + breakinfo[breakno].enabled = 0; + } return 0; } -void kgdb_remove_all_hw_break(void) +void bfin_remove_all_hw_break(void) { - memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8); -} + int breakno; -/* -void kgdb_show_info(void) -{ - printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n", - bfin_read_WPIA0(), bfin_read_WPIACNT0(), - bfin_read_WPIACTL(), bfin_read_WPSTAT()); + memset(breakinfo, 0, sizeof(struct hw_breakpoint)*HW_WATCHPOINT_NUM); + + for (breakno = 0; breakno < HW_INST_WATCHPOINT_NUM; breakno++) + breakinfo[breakno].type = TYPE_INST_WATCHPOINT; + for (; breakno < HW_WATCHPOINT_NUM; breakno++) + breakinfo[breakno].type = TYPE_DATA_WATCHPOINT; } -*/ -void kgdb_correct_hw_break(void) +void bfin_correct_hw_break(void) { int breakno; - int correctit; - uint32_t wpdactl = bfin_read_WPDACTL(); + unsigned int wpiactl = 0; + unsigned int wpdactl = 0; + int enable_wp = 0; + + for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) + if (breakinfo[breakno].enabled) { + enable_wp = 1; - correctit = 0; - for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) { - if (breakinfo[breakno].type == 1) { switch (breakno) { case 0: - if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) { - correctit = 1; - wpdactl &= ~(WPIREN01|EMUSW0); - wpdactl |= WPIAEN0|WPICNTEN0; - bfin_write_WPIA0(breakinfo[breakno].addr); - bfin_write_WPIACNT0(breakinfo[breakno].skip); - } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) { - correctit = 1; - wpdactl &= ~WPIAEN0; - } + wpiactl |= WPIAEN0|WPICNTEN0; + bfin_write_WPIA0(breakinfo[breakno].addr); + bfin_write_WPIACNT0(breakinfo[breakno].count + + breakinfo->skip); break; - case 1: - if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) { - correctit = 1; - wpdactl &= ~(WPIREN01|EMUSW1); - wpdactl |= WPIAEN1|WPICNTEN1; - bfin_write_WPIA1(breakinfo[breakno].addr); - bfin_write_WPIACNT1(breakinfo[breakno].skip); - } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) { - correctit = 1; - wpdactl &= ~WPIAEN1; - } + wpiactl |= WPIAEN1|WPICNTEN1; + bfin_write_WPIA1(breakinfo[breakno].addr); + bfin_write_WPIACNT1(breakinfo[breakno].count + + breakinfo->skip); break; - case 2: - if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) { - correctit = 1; - wpdactl &= ~(WPIREN23|EMUSW2); - wpdactl |= WPIAEN2|WPICNTEN2; - bfin_write_WPIA2(breakinfo[breakno].addr); - bfin_write_WPIACNT2(breakinfo[breakno].skip); - } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) { - correctit = 1; - wpdactl &= ~WPIAEN2; - } + wpiactl |= WPIAEN2|WPICNTEN2; + bfin_write_WPIA2(breakinfo[breakno].addr); + bfin_write_WPIACNT2(breakinfo[breakno].count + + breakinfo->skip); break; - case 3: - if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) { - correctit = 1; - wpdactl &= ~(WPIREN23|EMUSW3); - wpdactl |= WPIAEN3|WPICNTEN3; - bfin_write_WPIA3(breakinfo[breakno].addr); - bfin_write_WPIACNT3(breakinfo[breakno].skip); - } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) { - correctit = 1; - wpdactl &= ~WPIAEN3; - } + wpiactl |= WPIAEN3|WPICNTEN3; + bfin_write_WPIA3(breakinfo[breakno].addr); + bfin_write_WPIACNT3(breakinfo[breakno].count + + breakinfo->skip); break; case 4: - if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) { - correctit = 1; - wpdactl &= ~(WPIREN45|EMUSW4); - wpdactl |= WPIAEN4|WPICNTEN4; - bfin_write_WPIA4(breakinfo[breakno].addr); - bfin_write_WPIACNT4(breakinfo[breakno].skip); - } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) { - correctit = 1; - wpdactl &= ~WPIAEN4; - } + wpiactl |= WPIAEN4|WPICNTEN4; + bfin_write_WPIA4(breakinfo[breakno].addr); + bfin_write_WPIACNT4(breakinfo[breakno].count + + breakinfo->skip); break; case 5: - if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) { - correctit = 1; - wpdactl &= ~(WPIREN45|EMUSW5); - wpdactl |= WPIAEN5|WPICNTEN5; - bfin_write_WPIA5(breakinfo[breakno].addr); - bfin_write_WPIACNT5(breakinfo[breakno].skip); - } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) { - correctit = 1; - wpdactl &= ~WPIAEN5; - } + wpiactl |= WPIAEN5|WPICNTEN5; + bfin_write_WPIA5(breakinfo[breakno].addr); + bfin_write_WPIACNT5(breakinfo[breakno].count + + breakinfo->skip); + break; + case 6: + wpdactl |= WPDAEN0|WPDCNTEN0|WPDSRC0; + wpdactl |= breakinfo[breakno].dataacc + << WPDACC0_OFFSET; + bfin_write_WPDA0(breakinfo[breakno].addr); + bfin_write_WPDACNT0(breakinfo[breakno].count + + breakinfo->skip); + break; + case 7: + wpdactl |= WPDAEN1|WPDCNTEN1|WPDSRC1; + wpdactl |= breakinfo[breakno].dataacc + << WPDACC1_OFFSET; + bfin_write_WPDA1(breakinfo[breakno].addr); + bfin_write_WPDACNT1(breakinfo[breakno].count + + breakinfo->skip); break; } } - } - if (correctit) { - wpdactl &= ~WPAND; - wpdactl |= WPPWR; - /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/ + + /* Should enable WPPWR bit first before set any other + * WPIACTL and WPDACTL bits */ + if (enable_wp) { + bfin_write_WPIACTL(WPPWR); + CSYNC(); + bfin_write_WPIACTL(wpiactl|WPPWR); bfin_write_WPDACTL(wpdactl); CSYNC(); - /*kgdb_show_info();*/ } } void kgdb_disable_hw_debug(struct pt_regs *regs) { /* Disable hardware debugging while we are in kgdb */ - bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1); + bfin_write_WPIACTL(0); + bfin_write_WPDACTL(0); CSYNC(); } -void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code) +#ifdef CONFIG_SMP +void kgdb_passive_cpu_callback(void *info) +{ + kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); +} + +void kgdb_roundup_cpus(unsigned long flags) +{ + smp_call_function(kgdb_passive_cpu_callback, NULL, 0, 0); +} + +void kgdb_roundup_cpu(int cpu, unsigned long flags) +{ + smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0, 0); +} +#endif + +void kgdb_post_primary_code(struct pt_regs *regs, int eVector, int err_code) { /* Master processor is completely in the debugger */ - gdb_bf533vector = eVector; - gdb_bf533errcode = err_code; + gdb_bfin_vector = eVector; + gdb_bfin_errcode = err_code; } -int kgdb_arch_handle_exception(int exceptionVector, int signo, +int kgdb_arch_handle_exception(int vector, int signo, int err_code, char *remcom_in_buffer, char *remcom_out_buffer, - struct pt_regs *linux_regs) + struct pt_regs *regs) { long addr; long breakno; @@ -385,44 +404,40 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo, /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcom_in_buffer[1]; if (kgdb_hex2long(&ptr, &addr)) { - linux_regs->retx = addr; + regs->retx = addr; } - newPC = linux_regs->retx; + newPC = regs->retx; /* clear the trace bit */ - linux_regs->syscfg &= 0xfffffffe; + regs->syscfg &= 0xfffffffe; /* set the trace bit if we're stepping */ if (remcom_in_buffer[0] == 's') { - linux_regs->syscfg |= 0x1; - debugger_step = linux_regs->ipend; - debugger_step >>= 6; - for (i = 10; i > 0; i--, debugger_step >>= 1) - if (debugger_step & 1) + regs->syscfg |= 0x1; + kgdb_single_step = regs->ipend; + kgdb_single_step >>= 6; + for (i = 10; i > 0; i--, kgdb_single_step >>= 1) + if (kgdb_single_step & 1) break; /* i indicate event priority of current stopped instruction * user space instruction is 0, IVG15 is 1, IVTMR is 10. - * debugger_step > 0 means in single step mode + * kgdb_single_step > 0 means in single step mode */ - debugger_step = i + 1; - } else { - debugger_step = 0; + kgdb_single_step = i + 1; } - wp_status = bfin_read_WPSTAT(); - CSYNC(); - - if (exceptionVector == VEC_WATCH) { - for (breakno = 0; breakno < 6; ++breakno) { + if (vector == VEC_WATCH) { + wp_status = bfin_read_WPSTAT(); + for (breakno = 0; breakno < HW_WATCHPOINT_NUM; breakno++) { if (wp_status & (1 << breakno)) { breakinfo->skip = 1; break; } } + bfin_write_WPSTAT(0); } - kgdb_correct_hw_break(); - bfin_write_WPSTAT(0); + bfin_correct_hw_break(); return 0; } /* switch */ @@ -431,5 +446,385 @@ int kgdb_arch_handle_exception(int exceptionVector, int signo, struct kgdb_arch arch_kgdb_ops = { .gdb_bpt_instr = {0xa1}, +#ifdef CONFIG_SMP + .flags = KGDB_HW_BREAKPOINT|KGDB_THR_PROC_SWAP, +#else .flags = KGDB_HW_BREAKPOINT, +#endif + .set_hw_breakpoint = bfin_set_hw_break, + .remove_hw_breakpoint = bfin_remove_hw_break, + .remove_all_hw_break = bfin_remove_all_hw_break, + .correct_hw_break = bfin_correct_hw_break, }; + +static int hex(char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + if ((ch >= 'A') && (ch <= 'F')) + return ch - 'A' + 10; + return -1; +} + +static int validate_memory_access_address(unsigned long addr, int size) +{ + int cpu = raw_smp_processor_id(); + + if (size < 0) + return EFAULT; + if (addr >= 0x1000 && (addr + size) <= physical_mem_end) + return 0; + if (addr >= SYSMMR_BASE) + return 0; + if (addr >= ASYNC_BANK0_BASE + && addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) + return 0; + if (cpu == 0) { + if (addr >= L1_SCRATCH_START + && (addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)) + return 0; +#if L1_CODE_LENGTH != 0 + if (addr >= L1_CODE_START + && (addr + size <= L1_CODE_START + L1_CODE_LENGTH)) + return 0; +#endif +#if L1_DATA_A_LENGTH != 0 + if (addr >= L1_DATA_A_START + && (addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)) + return 0; +#endif +#if L1_DATA_B_LENGTH != 0 + if (addr >= L1_DATA_B_START + && (addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)) + return 0; +#endif +#ifdef CONFIG_SMP + } else if (cpu == 1) { + if (addr >= COREB_L1_SCRATCH_START + && (addr + size <= COREB_L1_SCRATCH_START + + L1_SCRATCH_LENGTH)) + return 0; +# if L1_CODE_LENGTH != 0 + if (addr >= COREB_L1_CODE_START + && (addr + size <= COREB_L1_CODE_START + L1_CODE_LENGTH)) + return 0; +# endif +# if L1_DATA_A_LENGTH != 0 + if (addr >= COREB_L1_DATA_A_START + && (addr + size <= COREB_L1_DATA_A_START + L1_DATA_A_LENGTH)) + return 0; +# endif +# if L1_DATA_B_LENGTH != 0 + if (addr >= COREB_L1_DATA_B_START + && (addr + size <= COREB_L1_DATA_B_START + L1_DATA_B_LENGTH)) + return 0; +# endif +#endif + } + +#if L2_LENGTH != 0 + if (addr >= L2_START + && addr + size <= L2_START + L2_LENGTH) + return 0; +#endif + + return EFAULT; +} + +/* + * Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null). May return an error. + */ +int kgdb_mem2hex(char *mem, char *buf, int count) +{ + char *tmp; + int err = 0; + unsigned char *pch; + unsigned short mmr16; + unsigned long mmr32; + int cpu = raw_smp_processor_id(); + + if (validate_memory_access_address((unsigned long)mem, count)) + return EFAULT; + + /* + * We use the upper half of buf as an intermediate buffer for the + * raw memory copy. Hex conversion will work against this one. + */ + tmp = buf + count; + + if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/ + switch (count) { + case 2: + if ((unsigned int)mem % 2 == 0) { + mmr16 = *(unsigned short *)mem; + pch = (unsigned char *)&mmr16; + *tmp++ = *pch++; + *tmp++ = *pch++; + tmp -= 2; + } else + err = EFAULT; + break; + case 4: + if ((unsigned int)mem % 4 == 0) { + mmr32 = *(unsigned long *)mem; + pch = (unsigned char *)&mmr32; + *tmp++ = *pch++; + *tmp++ = *pch++; + *tmp++ = *pch++; + *tmp++ = *pch++; + tmp -= 4; + } else + err = EFAULT; + break; + default: + err = EFAULT; + } + } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START && + (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH +#ifdef CONFIG_SMP + || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START && + (unsigned int)(mem + count) <= + COREB_L1_CODE_START + L1_CODE_LENGTH +#endif + ) { + /* access L1 instruction SRAM*/ + if (dma_memcpy(tmp, mem, count) == NULL) + err = EFAULT; + } else + err = probe_kernel_read(tmp, mem, count); + + if (!err) { + while (count > 0) { + buf = pack_hex_byte(buf, *tmp); + tmp++; + count--; + } + + *buf = 0; + } + + return err; +} + +/* + * Copy the binary array pointed to by buf into mem. Fix $, #, and + * 0x7d escaped with 0x7d. Return a pointer to the character after + * the last byte written. + */ +int kgdb_ebin2mem(char *buf, char *mem, int count) +{ + char *tmp_old; + char *tmp_new; + unsigned short *mmr16; + unsigned long *mmr32; + int err = 0; + int size = 0; + int cpu = raw_smp_processor_id(); + + tmp_old = tmp_new = buf; + + while (count-- > 0) { + if (*tmp_old == 0x7d) + *tmp_new = *(++tmp_old) ^ 0x20; + else + *tmp_new = *tmp_old; + tmp_new++; + tmp_old++; + size++; + } + + if (validate_memory_access_address((unsigned long)mem, size)) + return EFAULT; + + if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/ + switch (size) { + case 2: + if ((unsigned int)mem % 2 == 0) { + mmr16 = (unsigned short *)buf; + *(unsigned short *)mem = *mmr16; + } else + return EFAULT; + break; + case 4: + if ((unsigned int)mem % 4 == 0) { + mmr32 = (unsigned long *)buf; + *(unsigned long *)mem = *mmr32; + } else + return EFAULT; + break; + default: + return EFAULT; + } + } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START && + (unsigned int)(mem + count) < L1_CODE_START + L1_CODE_LENGTH +#ifdef CONFIG_SMP + || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START && + (unsigned int)(mem + count) <= + COREB_L1_CODE_START + L1_CODE_LENGTH +#endif + ) { + /* access L1 instruction SRAM */ + if (dma_memcpy(mem, buf, size) == NULL) + err = EFAULT; + } else + err = probe_kernel_write(mem, buf, size); + + return err; +} + +/* + * Convert the hex array pointed to by buf into binary to be placed in mem. + * Return a pointer to the character AFTER the last byte written. + * May return an error. + */ +int kgdb_hex2mem(char *buf, char *mem, int count) +{ + char *tmp_raw; + char *tmp_hex; + unsigned short *mmr16; + unsigned long *mmr32; + int cpu = raw_smp_processor_id(); + + if (validate_memory_access_address((unsigned long)mem, count)) + return EFAULT; + + /* + * We use the upper half of buf as an intermediate buffer for the + * raw memory that is converted from hex. + */ + tmp_raw = buf + count * 2; + + tmp_hex = tmp_raw - 1; + while (tmp_hex >= buf) { + tmp_raw--; + *tmp_raw = hex(*tmp_hex--); + *tmp_raw |= hex(*tmp_hex--) << 4; + } + + if ((unsigned int)mem >= SYSMMR_BASE) { /*access MMR registers*/ + switch (count) { + case 2: + if ((unsigned int)mem % 2 == 0) { + mmr16 = (unsigned short *)tmp_raw; + *(unsigned short *)mem = *mmr16; + } else + return EFAULT; + break; + case 4: + if ((unsigned int)mem % 4 == 0) { + mmr32 = (unsigned long *)tmp_raw; + *(unsigned long *)mem = *mmr32; + } else + return EFAULT; + break; + default: + return EFAULT; + } + } else if (cpu == 0 && (unsigned int)mem >= L1_CODE_START && + (unsigned int)(mem + count) <= L1_CODE_START + L1_CODE_LENGTH +#ifdef CONFIG_SMP + || cpu == 1 && (unsigned int)mem >= COREB_L1_CODE_START && + (unsigned int)(mem + count) <= + COREB_L1_CODE_START + L1_CODE_LENGTH +#endif + ) { + /* access L1 instruction SRAM */ + if (dma_memcpy(mem, tmp_raw, count) == NULL) + return EFAULT; + } else + return probe_kernel_write(mem, tmp_raw, count); + return 0; +} + +int kgdb_validate_break_address(unsigned long addr) +{ + int cpu = raw_smp_processor_id(); + + if (addr >= 0x1000 && (addr + BREAK_INSTR_SIZE) <= physical_mem_end) + return 0; + if (addr >= ASYNC_BANK0_BASE + && addr + BREAK_INSTR_SIZE <= ASYNC_BANK3_BASE + ASYNC_BANK3_BASE) + return 0; +#if L1_CODE_LENGTH != 0 + if (cpu == 0 && addr >= L1_CODE_START + && addr + BREAK_INSTR_SIZE <= L1_CODE_START + L1_CODE_LENGTH) + return 0; +# ifdef CONFIG_SMP + else if (cpu == 1 && addr >= COREB_L1_CODE_START + && addr + BREAK_INSTR_SIZE <= COREB_L1_CODE_START + L1_CODE_LENGTH) + return 0; +# endif +#endif +#if L2_LENGTH != 0 + if (addr >= L2_START + && addr + BREAK_INSTR_SIZE <= L2_START + L2_LENGTH) + return 0; +#endif + + return EFAULT; +} + +int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr) +{ + int err; + int cpu = raw_smp_processor_id(); + + if ((cpu == 0 && (unsigned int)addr >= L1_CODE_START + && (unsigned int)(addr + BREAK_INSTR_SIZE) + < L1_CODE_START + L1_CODE_LENGTH) +#ifdef CONFIG_SMP + || (cpu == 1 && (unsigned int)addr >= COREB_L1_CODE_START + && (unsigned int)(addr + BREAK_INSTR_SIZE) + < COREB_L1_CODE_START + L1_CODE_LENGTH) +#endif + ) { + /* access L1 instruction SRAM */ + if (dma_memcpy(saved_instr, (void *)addr, BREAK_INSTR_SIZE) + == NULL) + return -EFAULT; + + if (dma_memcpy((void *)addr, arch_kgdb_ops.gdb_bpt_instr, + BREAK_INSTR_SIZE) == NULL) + return -EFAULT; + + return 0; + } else { + err = probe_kernel_read(saved_instr, (char *)addr, + BREAK_INSTR_SIZE); + if (err) + return err; + + return probe_kernel_write((char *)addr, + arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); + } +} + +int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle) +{ + if ((unsigned int)addr >= L1_CODE_START && + (unsigned int)(addr + BREAK_INSTR_SIZE) < + L1_CODE_START + L1_CODE_LENGTH) { + /* access L1 instruction SRAM */ + if (dma_memcpy((void *)addr, bundle, BREAK_INSTR_SIZE) == NULL) + return -EFAULT; + + return 0; + } else + return probe_kernel_write((char *)addr, + (char *)bundle, BREAK_INSTR_SIZE); +} + +int kgdb_arch_init(void) +{ + kgdb_single_step = 0; + + bfin_remove_all_hw_break(); + return 0; +} + +void kgdb_arch_exit(void) +{ +} diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index bd41fca315dd..8d561baef896 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -43,12 +43,11 @@ #include #ifdef CONFIG_KGDB -# include # include # define CHK_DEBUGGER_TRAP() \ do { \ - CHK_DEBUGGER(trapnr, sig, info.si_code, fp, ); \ + kgdb_handle_exception(trapnr, sig, info.si_code, fp); \ } while (0) # define CHK_DEBUGGER_TRAP_MAYBE() \ do { \ @@ -300,7 +299,7 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = SEGV_STACKFLOW; sig = SIGSEGV; printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x04 - User Defined, Caught by default */ /* 0x05 - User Defined, Caught by default */ @@ -329,7 +328,7 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = TRAP_TRACEFLOW; sig = SIGTRAP; printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x12 - Reserved, Caught by default */ /* 0x13 - Reserved, Caught by default */ @@ -351,35 +350,35 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = ILL_ILLOPC; sig = SIGILL; printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x22 - Illegal Instruction Combination, handled here */ case VEC_ILGAL_I: info.si_code = ILL_ILLPARAOP; sig = SIGILL; printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x23 - Data CPLB protection violation, handled here */ case VEC_CPLB_VL: info.si_code = ILL_CPLB_VI; sig = SIGBUS; printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x24 - Data access misaligned, handled here */ case VEC_MISALI_D: info.si_code = BUS_ADRALN; sig = SIGBUS; printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x25 - Unrecoverable Event, handled here */ case VEC_UNCOV: info.si_code = ILL_ILLEXCPT; sig = SIGILL; printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, error case is handled here */ @@ -387,7 +386,6 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = BUS_ADRALN; sig = SIGBUS; printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); break; /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ case VEC_CPLB_MHIT: @@ -399,7 +397,7 @@ asmlinkage void trap_c(struct pt_regs *fp) else #endif printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x28 - Emulation Watchpoint, handled here */ case VEC_WATCH: @@ -418,7 +416,7 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = BUS_OPFETCH; sig = SIGBUS; printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n"); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; #else /* 0x29 - Reserved, Caught by default */ @@ -428,21 +426,20 @@ asmlinkage void trap_c(struct pt_regs *fp) info.si_code = BUS_ADRALN; sig = SIGBUS; printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2B - Instruction CPLB protection violation, handled here */ case VEC_CPLB_I_VL: info.si_code = ILL_CPLB_VI; sig = SIGBUS; printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ case VEC_CPLB_I_M: info.si_code = ILL_CPLB_MISS; sig = SIGBUS; printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); break; /* 0x2D - Instruction CPLB Multiple Hits, handled here */ case VEC_CPLB_I_MHIT: @@ -454,14 +451,14 @@ asmlinkage void trap_c(struct pt_regs *fp) else #endif printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2E - Illegal use of Supervisor Resource, handled here */ case VEC_ILL_RES: info.si_code = ILL_PRVOPC; sig = SIGILL; printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2F - Reserved, Caught by default */ /* 0x30 - Reserved, Caught by default */ @@ -508,14 +505,14 @@ asmlinkage void trap_c(struct pt_regs *fp) printk(KERN_NOTICE HWC_default(KERN_NOTICE)); break; } - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; default: info.si_code = TRAP_ILLTRAP; sig = SIGTRAP; printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", (fp->seqstat & SEQSTAT_EXCAUSE)); - CHK_DEBUGGER_TRAP(); + CHK_DEBUGGER_TRAP_MAYBE(); break; } diff --git a/arch/blackfin/mach-bf561/include/mach/mem_map.h b/arch/blackfin/mach-bf561/include/mach/mem_map.h index c26d8486cc4b..9d6674ad1e5e 100644 --- a/arch/blackfin/mach-bf561/include/mach/mem_map.h +++ b/arch/blackfin/mach-bf561/include/mach/mem_map.h @@ -35,9 +35,16 @@ /* Memory Map for ADSP-BF561 processors */ #ifdef CONFIG_BF561 -#define L1_CODE_START 0xFFA00000 -#define L1_DATA_A_START 0xFF800000 -#define L1_DATA_B_START 0xFF900000 +#define COREA_L1_CODE_START 0xFFA00000 +#define COREA_L1_DATA_A_START 0xFF800000 +#define COREA_L1_DATA_B_START 0xFF900000 +#define COREB_L1_CODE_START 0xFF600000 +#define COREB_L1_DATA_A_START 0xFF500000 +#define COREB_L1_DATA_B_START 0xFF400000 + +#define L1_CODE_START COREA_L1_CODE_START +#define L1_DATA_A_START COREA_L1_DATA_A_START +#define L1_DATA_B_START COREA_L1_DATA_B_START #define L1_CODE_LENGTH 0x4000 @@ -72,7 +79,10 @@ /* Scratch Pad Memory */ -#define L1_SCRATCH_START 0xFFB00000 +#define COREA_L1_SCRATCH_START 0xFFB00000 +#define COREB_L1_SCRATCH_START 0xFF700000 + +#define L1_SCRATCH_START COREA_L1_SCRATCH_START #define L1_SCRATCH_LENGTH 0x1000 #endif /* _MEM_MAP_533_H_ */ diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 90c7397036ed..5a219b228de3 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -190,8 +190,8 @@ ENTRY(_ex_single_step) if cc jump .Lfind_priority_done; jump.s .Lfind_priority_start; .Lfind_priority_done: - p4.l = _debugger_step; - p4.h = _debugger_step; + p4.l = _kgdb_single_step; + p4.h = _kgdb_single_step; r6 = [p4]; cc = r6 == 0; if cc jump .Ldo_single_step; @@ -1071,7 +1071,12 @@ ENTRY(_ex_table) */ .long _ex_syscall /* 0x00 - User Defined - Linux Syscall */ .long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */ +#ifdef CONFIG_KGDB + .long _ex_trap_c /* 0x02 - User Defined - KGDB initial connection + and break signal trap */ +#else .long _ex_replaceable /* 0x02 - User Defined */ +#endif .long _ex_trap_c /* 0x03 - User Defined - userspace stack overflow */ .long _ex_trap_c /* 0x04 - User Defined - dump trace buffer */ .long _ex_replaceable /* 0x05 - User Defined */ diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 5fa536727c61..ff4d5c2879a5 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -1136,8 +1136,4 @@ void do_irq(int vec, struct pt_regs *fp) vec = ivg->irqno; } asm_do_IRQ(vec, fp); - -#ifdef CONFIG_KGDB - kgdb_process_breakpoint(); -#endif } -- cgit v1.2.3-58-ga151 From 5c64e0d5109532f8184be29c1dc163059e3ded4b Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 8 Oct 2008 14:43:47 +0800 Subject: Blackfin arch: Better error handling of unknown exceptions Better error handling of unknown exceptions, allows userspace to do a EXCPT n instruction for a not installed exception handler, and the kernel doesn't crash (like it use to before this). Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/traps.h | 5 ++++- arch/blackfin/kernel/traps.c | 43 ++++++++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 15 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/traps.h b/arch/blackfin/include/asm/traps.h index f0e5f940d9ca..34f7295fb070 100644 --- a/arch/blackfin/include/asm/traps.h +++ b/arch/blackfin/include/asm/traps.h @@ -59,6 +59,9 @@ level " or a 16-bit register is accessed with a 32-bit instruction.\n" #define HWC_x3(level) \ "External Memory Addressing Error\n" +#define EXC_0x04(level) \ + "Unimplmented exception occured\n" \ + level " - Maybe you forgot to install a custom exception handler?\n" #define HWC_x12(level) \ "Performance Monitor Overflow\n" #define HWC_x18(level) \ @@ -84,7 +87,7 @@ level " a particular processor implementation.\n" #define EXC_0x22(level) \ "Illegal instruction combination\n" \ - level " - See section for multi-issue rules in the ADSP-BF53x Blackfin\n" \ + level " - See section for multi-issue rules in the Blackfin\n" \ level " Processor Instruction Set Reference.\n" #define EXC_0x23(level) \ "Data access CPLB protection violation\n" \ diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 8d561baef896..be5ae7fabc5f 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -301,18 +301,28 @@ asmlinkage void trap_c(struct pt_regs *fp) printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; - /* 0x04 - User Defined, Caught by default */ - /* 0x05 - User Defined, Caught by default */ - /* 0x06 - User Defined, Caught by default */ - /* 0x07 - User Defined, Caught by default */ - /* 0x08 - User Defined, Caught by default */ - /* 0x09 - User Defined, Caught by default */ - /* 0x0A - User Defined, Caught by default */ - /* 0x0B - User Defined, Caught by default */ - /* 0x0C - User Defined, Caught by default */ - /* 0x0D - User Defined, Caught by default */ - /* 0x0E - User Defined, Caught by default */ - /* 0x0F - User Defined, Caught by default */ + /* 0x04 - User Defined */ + /* 0x05 - User Defined */ + /* 0x06 - User Defined */ + /* 0x07 - User Defined */ + /* 0x08 - User Defined */ + /* 0x09 - User Defined */ + /* 0x0A - User Defined */ + /* 0x0B - User Defined */ + /* 0x0C - User Defined */ + /* 0x0D - User Defined */ + /* 0x0E - User Defined */ + /* 0x0F - User Defined */ + /* + * If we got here, it is most likely that someone was trying to use a + * custom exception handler, and it is not actually installed properly + */ + case VEC_EXCPT04 ... VEC_EXCPT15: + info.si_code = ILL_ILLPARAOP; + sig = SIGILL; + printk(KERN_NOTICE EXC_0x04(KERN_NOTICE)); + CHK_DEBUGGER_TRAP_MAYBE(); + break; /* 0x10 HW Single step, handled here */ case VEC_STEP: info.si_code = TRAP_STEP; @@ -507,9 +517,14 @@ asmlinkage void trap_c(struct pt_regs *fp) } CHK_DEBUGGER_TRAP_MAYBE(); break; + /* + * We should be handling all known exception types above, + * if we get here we hit a reserved one, so panic + */ default: - info.si_code = TRAP_ILLTRAP; - sig = SIGTRAP; + oops_in_progress = 1; + info.si_code = ILL_ILLPARAOP; + sig = SIGILL; printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", (fp->seqstat & SEQSTAT_EXCAUSE)); CHK_DEBUGGER_TRAP_MAYBE(); -- cgit v1.2.3-58-ga151 From fffe53bee7d90ab2103d2520ab4d095aea9b7397 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 8 Oct 2008 14:46:09 +0800 Subject: Blackfin arch: fix bug - sometimes there is no response to the hitting key in uboot for bf561-ezkit when running with 50mhz SCLK use 10 delays rather than 7 Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/reboot.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c index 367e2dc09881..b0a8f89cc9b6 100644 --- a/arch/blackfin/kernel/reboot.c +++ b/arch/blackfin/kernel/reboot.c @@ -34,15 +34,15 @@ void bfin_reset(void) bfin_write_SWRST(0x7); /* Due to the way reset is handled in the hardware, we need - * to delay for 7 SCLKS. The only reliable way to do this is - * to calculate the CCLK/SCLK ratio and multiply 7. For now, + * to delay for 10 SCLKS. The only reliable way to do this is + * to calculate the CCLK/SCLK ratio and multiply 10. For now, * we'll assume worse case which is a 1:15 ratio. */ asm( "LSETUP (1f, 1f) LC0 = %0\n" "1: nop;" : - : "a" (15 * 7) + : "a" (15 * 10) : "LC0", "LB0", "LT0" ); -- cgit v1.2.3-58-ga151 From 74c04503d777b5d1f8f2e38852df4f1a6c82fc7b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 8 Oct 2008 16:13:17 +0800 Subject: Blackfin arch: mark local gpio_error() as static Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index ecbd141e0ef2..12710ed180be 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -231,7 +231,7 @@ inline int check_gpio(unsigned gpio) } #endif -void gpio_error(unsigned gpio) +static void gpio_error(unsigned gpio) { printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio); } -- cgit v1.2.3-58-ga151 From 7d98c881eed9e19767bc77ffd650d0041b4f41ec Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 8 Oct 2008 16:29:01 +0800 Subject: Blackfin arch: Make sure we protect except 2 properly, and print out memory properly Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index be5ae7fabc5f..0112ba407f63 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -317,6 +317,7 @@ asmlinkage void trap_c(struct pt_regs *fp) * If we got here, it is most likely that someone was trying to use a * custom exception handler, and it is not actually installed properly */ + case VEC_EXCPT02: case VEC_EXCPT04 ... VEC_EXCPT15: info.si_code = ILL_ILLPARAOP; sig = SIGILL; @@ -968,7 +969,7 @@ void dump_bfin_mem(struct pt_regs *fp) if (!((unsigned long)addr & 0xF)) printk("\n" KERN_NOTICE "0x%p: ", addr); - if (get_instruction(&val, addr)) { + if (!get_instruction(&val, addr)) { val = 0; sprintf(buf, "????"); } else -- cgit v1.2.3-58-ga151 From 5b04f271fe49bb7adb061de454d383c027a18de0 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 8 Oct 2008 17:32:57 +0800 Subject: Blackfin arch: Modify some funtion names to more genernal ones Signed-off-by: Graf Yang Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/cplbinit.h | 2 +- arch/blackfin/kernel/cplb-mpu/cplbinit.c | 2 +- arch/blackfin/kernel/cplb-nompu/cplbinit.c | 2 +- arch/blackfin/kernel/setup.c | 8 ++++---- arch/blackfin/mach-common/head.S | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/cplbinit.h b/arch/blackfin/include/asm/cplbinit.h index 0eb1c1b685a7..9d23cd1ff7d9 100644 --- a/arch/blackfin/include/asm/cplbinit.h +++ b/arch/blackfin/include/asm/cplbinit.h @@ -90,6 +90,6 @@ extern u_long dpdt_swapcount_table[]; extern unsigned long reserved_mem_dcache_on; extern unsigned long reserved_mem_icache_on; -extern void generate_cpl_tables(void); +extern void generate_cplb_tables(void); #endif diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c index 48060105346a..d4257d0ad6a8 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c @@ -36,7 +36,7 @@ struct cplb_entry dcplb_tbl[MAX_CPLBS]; int first_switched_icplb, first_switched_dcplb; int first_mask_dcplb; -void __init generate_cpl_tables(void) +void __init generate_cplb_tables(void) { int i_d, i_i; unsigned long addr; diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c index 728f708d3981..2c45c16c3520 100644 --- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c @@ -308,7 +308,7 @@ __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end) } } -void __init generate_cpl_tables(void) +void __init generate_cplb_tables(void) { u16 i, j, process; diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 8e639dc886a3..ea4f60978c66 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -78,10 +78,10 @@ static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata; static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata; static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata; -void __init bf53x_cache_init(void) +void __init bfin_cache_init(void) { #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) - generate_cpl_tables(); + generate_cplb_tables(); #endif #ifdef CONFIG_BFIN_ICACHE @@ -101,7 +101,7 @@ void __init bf53x_cache_init(void) #endif } -void __init bf53x_relocate_l1_mem(void) +void __init bfin_relocate_l1_mem(void) { unsigned long l1_code_length; unsigned long l1_data_a_length; @@ -860,7 +860,7 @@ void __init setup_arch(char **cmdline_p) != SAFE_USER_INSTRUCTION - FIXED_CODE_START); init_exception_vectors(); - bf53x_cache_init(); + bfin_cache_init(); } static int __init topology_init(void) diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index 7cb21cfcbf28..eb9eef0e23b7 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -141,7 +141,7 @@ ENTRY(__start) #endif /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ - call _bf53x_relocate_l1_mem; + call _bfin_relocate_l1_mem; #ifdef CONFIG_BFIN_KERNEL_CLOCK call _start_dma_code; #endif -- cgit v1.2.3-58-ga151 From 9df10281e1c03b1c04d17f387bc59eb932c0bb87 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Wed, 8 Oct 2008 18:03:33 +0800 Subject: Blackfin arch: Use DTEST rather than DMA to poke at L1 SRAM during exception context Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/bfin-global.h | 2 + arch/blackfin/kernel/traps.c | 3 +- arch/blackfin/mach-common/head.S | 10 ++ arch/blackfin/mm/Makefile | 2 +- arch/blackfin/mm/isram-driver.c | 201 ++++++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 arch/blackfin/mm/isram-driver.c (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h index 7ba70de66f2b..e1f9cbd00a09 100644 --- a/arch/blackfin/include/asm/bfin-global.h +++ b/arch/blackfin/include/asm/bfin-global.h @@ -92,6 +92,8 @@ extern int sram_free(const void*); extern void *sram_alloc_with_lsl(size_t, unsigned long); extern int sram_free_with_lsl(const void*); +extern void *isram_memcpy(void *dest, const void *src, size_t n); + extern const char bfin_board_name[]; extern unsigned long bfin_sic_iwr[]; diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 0112ba407f63..89cff2c7e8b1 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -40,7 +40,6 @@ #include #include #include -#include #ifdef CONFIG_KGDB # include @@ -632,7 +631,7 @@ bool get_instruction(unsigned short *val, unsigned short *address) #if L1_CODE_LENGTH != 0 if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) { - dma_memcpy(val, address, 2); + isram_memcpy(val, address, 2); return true; } #endif diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index eb9eef0e23b7..3069df580729 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -68,6 +68,16 @@ ENTRY(__start) M2 = r0; M3 = r0; + /* + * Clear ITEST_COMMAND and DTEST_COMMAND registers, + * Leaving these as non-zero can confuse the emulator + */ + p0.L = LO(DTEST_COMMAND); + p0.H = HI(DTEST_COMMAND); + [p0] = R0; + [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0; + CSYNC; + trace_buffer_init(p0,r0); P0 = R1; R0 = R1; diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile index 81aacbc32d3c..d489f894f4b1 100644 --- a/arch/blackfin/mm/Makefile +++ b/arch/blackfin/mm/Makefile @@ -2,4 +2,4 @@ # arch/blackfin/mm/Makefile # -obj-y := sram-alloc.o init.o +obj-y := sram-alloc.o isram-driver.o init.o diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c new file mode 100644 index 000000000000..22913e7a1818 --- /dev/null +++ b/arch/blackfin/mm/isram-driver.c @@ -0,0 +1,201 @@ +/* + * Description: Instruction SRAM accessor functions for the Blackfin + * + * Copyright 2008 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include + +/* + * IMPORTANT WARNING ABOUT THESE FUNCTIONS + * + * The emulator will not function correctly if a write command is left in + * ITEST_COMMAND or DTEST_COMMAND AND access to cache memory is needed by + * the emulator. To avoid such problems, ensure that both ITEST_COMMAND + * and DTEST_COMMAND are zero when exiting these functions. + */ + + +/* + * On the Blackfin, L1 instruction sram (which operates at core speeds) can not + * be accessed by a normal core load, so we need to go through a few hoops to + * read/write it. + * To try to make it easier - we export a memcpy interface, where either src or + * dest can be in this special L1 memory area. + * The low level read/write functions should not be exposed to the rest of the + * kernel, since they operate on 64-bit data, and need specific address alignment + */ + +static DEFINE_SPINLOCK(dtest_lock); + +/* Takes a void pointer */ +#define IADDR2DTEST(x) \ + ({ unsigned long __addr = (unsigned long)(x); \ + (__addr & 0x47F8) | /* address bits 14 & 10:3 */ \ + (__addr & 0x0800) << 15 | /* address bit 11 */ \ + (__addr & 0x3000) << 4 | /* address bits 13:12 */ \ + (__addr & 0x8000) << 8 | /* address bit 15 */ \ + (0x1000004); /* isram access */ \ + }) + +/* Takes a pointer, and returns the offset (in bits) which things should be shifted */ +#define ADDR2OFFSET(x) ((((unsigned long)(x)) & 0x7) * 8) + +/* Takes a pointer, determines if it is the last byte in the isram 64-bit data type */ +#define ADDR2LAST(x) ((((unsigned long)x) & 0x7) == 0x7) + +static void isram_write(const void *addr, uint64_t data) +{ + uint32_t cmd; + unsigned long flags; + + if (addr >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) + return; + + cmd = IADDR2DTEST(addr) | 1; /* write */ + + /* + * Writes to DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND + * While in exception context - atomicity is guaranteed or double fault + */ + spin_lock_irqsave(&dtest_lock, flags); + + bfin_write_DTEST_DATA0(data & 0xFFFFFFFF); + bfin_write_DTEST_DATA1(data >> 32); + + /* use the builtin, since interrupts are already turned off */ + __builtin_bfin_csync(); + bfin_write_DTEST_COMMAND(cmd); + __builtin_bfin_csync(); + + bfin_write_DTEST_COMMAND(0); + __builtin_bfin_csync(); + + spin_unlock_irqrestore(&dtest_lock, flags); +} + +static uint64_t isram_read(const void *addr) +{ + uint32_t cmd; + unsigned long flags; + uint64_t ret; + + if (addr > (void *)(L1_CODE_START + L1_CODE_LENGTH)) + return 0; + + cmd = IADDR2DTEST(addr) | 0; /* read */ + + /* + * Reads of DTEST_DATA[0:1] need to be atomic with write to DTEST_COMMAND + * While in exception context - atomicity is guaranteed or double fault + */ + spin_lock_irqsave(&dtest_lock, flags); + /* use the builtin, since interrupts are already turned off */ + __builtin_bfin_csync(); + bfin_write_DTEST_COMMAND(cmd); + __builtin_bfin_csync(); + ret = bfin_read_DTEST_DATA0() | ((uint64_t)bfin_read_DTEST_DATA1() << 32); + + bfin_write_DTEST_COMMAND(0); + __builtin_bfin_csync(); + spin_unlock_irqrestore(&dtest_lock, flags); + + return ret; +} + +static bool isram_check_addr(const void *addr, size_t n) +{ + if ((addr >= (void *)L1_CODE_START) && + (addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))) { + if ((addr + n) >= (void *)(L1_CODE_START + L1_CODE_LENGTH)) { + show_stack(NULL, NULL); + printk(KERN_ERR "isram_memcpy: copy involving %p length " + "(%zu) too long\n", addr, n); + } + return true; + } + return false; +} + +/* + * The isram_memcpy() function copies n bytes from memory area src to memory area dest. + * The isram_memcpy() function returns a pointer to dest. + * Either dest or src can be in L1 instruction sram. + */ +void *isram_memcpy(void *dest, const void *src, size_t n) +{ + uint64_t data_in = 0, data_out = 0; + size_t count; + bool dest_in_l1, src_in_l1, need_data, put_data; + unsigned char byte, *src_byte, *dest_byte; + + src_byte = (unsigned char *)src; + dest_byte = (unsigned char *)dest; + + dest_in_l1 = isram_check_addr(dest, n); + src_in_l1 = isram_check_addr(src, n); + + need_data = true; + put_data = true; + for (count = 0; count < n; count++) { + if (src_in_l1) { + if (need_data) { + data_in = isram_read(src + count); + need_data = false; + } + + if (ADDR2LAST(src + count)) + need_data = true; + + byte = (unsigned char)((data_in >> ADDR2OFFSET(src + count)) & 0xff); + + } else { + /* src is in L2 or L3 - so just dereference*/ + byte = src_byte[count]; + } + + if (dest_in_l1) { + if (put_data) { + data_out = isram_read(dest + count); + put_data = false; + } + + data_out &= ~((uint64_t)0xff << ADDR2OFFSET(dest + count)); + data_out |= ((uint64_t)byte << ADDR2OFFSET(dest + count)); + + if (ADDR2LAST(dest + count)) { + put_data = true; + isram_write(dest + count, data_out); + } + } else { + /* dest in L2 or L3 - so just dereference */ + dest_byte[count] = byte; + } + } + + /* make sure we dump the last byte if necessary */ + if (dest_in_l1 && !put_data) + isram_write(dest + count, data_out); + + return dest; +} +EXPORT_SYMBOL(isram_memcpy); + -- cgit v1.2.3-58-ga151 From 27707d3e43e3a9c53e75cd7769f3ef74b1d56625 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 9 Oct 2008 14:04:41 +0800 Subject: Blackfin arch: Fix bug - kernel build with config kernel debugging with remote gdb fails Add some comment and fix duplicated VEC_EXCPT02 Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 89cff2c7e8b1..1a3c4daf557a 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -284,15 +284,6 @@ asmlinkage void trap_c(struct pt_regs *fp) return; else break; -#ifdef CONFIG_KGDB - case VEC_EXCPT02 : /* gdb connection */ - info.si_code = TRAP_ILLTRAP; - sig = SIGTRAP; - CHK_DEBUGGER_TRAP(); - return; -#else - /* 0x02 - User Defined, Caught by default */ -#endif /* 0x03 - User Defined, userspace stack overflow */ case VEC_EXCPT03: info.si_code = SEGV_STACKFLOW; @@ -300,6 +291,14 @@ asmlinkage void trap_c(struct pt_regs *fp) printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; + /* 0x02 - KGDB initial connection and break signal trap */ + case VEC_EXCPT02: +#ifdef CONFIG_KGDB + info.si_code = TRAP_ILLTRAP; + sig = SIGTRAP; + CHK_DEBUGGER_TRAP(); + return; +#endif /* 0x04 - User Defined */ /* 0x05 - User Defined */ /* 0x06 - User Defined */ @@ -312,11 +311,9 @@ asmlinkage void trap_c(struct pt_regs *fp) /* 0x0D - User Defined */ /* 0x0E - User Defined */ /* 0x0F - User Defined */ - /* - * If we got here, it is most likely that someone was trying to use a + /* If we got here, it is most likely that someone was trying to use a * custom exception handler, and it is not actually installed properly */ - case VEC_EXCPT02: case VEC_EXCPT04 ... VEC_EXCPT15: info.si_code = ILL_ILLPARAOP; sig = SIGILL; -- cgit v1.2.3-58-ga151 From f099f39acf7575eff3dee3c562cec4e592876c33 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Thu, 9 Oct 2008 14:11:57 +0800 Subject: Blackfin arch: Make L2 SRAM cacheable Signed-off-by: Sonic Zhang Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 7 +++++++ arch/blackfin/include/asm/cplb.h | 8 +++++++- arch/blackfin/kernel/cplb-mpu/cplbinit.c | 10 ++++++++++ arch/blackfin/kernel/cplb-nompu/cplbinit.c | 4 ++-- 4 files changed, 26 insertions(+), 3 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 554ac5827c1d..10c97efbd91f 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -772,6 +772,13 @@ config BFIN_WT endchoice +config BFIN_L2_CACHEABLE + bool "Cache L2 SRAM" + depends on (BFIN_DCACHE || BFIN_ICACHE) && (BF54x || BF561) + default n + help + Select to make L2 SRAM cacheable in L1 data and instruction cache. + config MPU bool "Enable the memory protection unit (EXPERIMENTAL)" default n diff --git a/arch/blackfin/include/asm/cplb.h b/arch/blackfin/include/asm/cplb.h index 05d6f05fb748..9e8b4035fcec 100644 --- a/arch/blackfin/include/asm/cplb.h +++ b/arch/blackfin/include/asm/cplb.h @@ -55,7 +55,13 @@ #endif #define L1_DMEMORY (CPLB_LOCK | CPLB_COMMON) -#define L2_MEMORY (CPLB_COMMON) +#ifdef CONFIG_BFIN_L2_CACHEABLE +#define L2_IMEMORY (SDRAM_IGENERIC) +#define L2_DMEMORY (SDRAM_DGENERIC) +#else +#define L2_IMEMORY (CPLB_COMMON) +#define L2_DMEMORY (CPLB_COMMON) +#endif #define SDRAM_DNON_CHBL (CPLB_COMMON) #define SDRAM_EBIU (CPLB_COMMON) #define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY) diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c index d4257d0ad6a8..55af729f8495 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c @@ -83,8 +83,18 @@ void __init generate_cplb_tables(void) dcplb_tbl[i_d].addr = L1_DATA_A_START; dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB; #endif +#if L1_CODE_LENGTH > 0 icplb_tbl[i_i].addr = L1_CODE_START; icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB; +#endif + + /* Cover L2 memory */ +#if L2_LENGTH > 0 + dcplb_tbl[i_d].addr = L2_START; + dcplb_tbl[i_d++].data = L2_DMEMORY | PAGE_SIZE_1MB; + icplb_tbl[i_i].addr = L2_START; + icplb_tbl[i_i++].data = L2_IMEMORY | PAGE_SIZE_1MB; +#endif first_mask_dcplb = i_d; first_switched_dcplb = i_d + (1 << page_mask_order); diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c index 2c45c16c3520..301252e84441 100644 --- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c @@ -168,8 +168,8 @@ static struct cplb_desc cplb_data[] = { .end = L2_START + L2_LENGTH, .psize = SIZE_1M, .attr = SWITCH_T | I_CPLB | D_CPLB, - .i_conf = L2_MEMORY, - .d_conf = L2_MEMORY, + .i_conf = L2_IMEMORY, + .d_conf = L2_DMEMORY, .valid = (L2_LENGTH > 0), .name = "L2 Memory", }, -- cgit v1.2.3-58-ga151 From dabaad5b90dec6909c984d95330f6f41c325f9a8 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Oct 2008 15:17:36 +0800 Subject: Blackfin arch: fix bug -- PTRACE_PEEKDATA does not seem to work which breaks umoven() in strace Don't add arbitrary offset when peeking at data Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/ptrace.c | 66 ++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 35 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index bf1a51d8e608..9ce80d05e2c9 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -46,7 +46,6 @@ #include #include -#define MAX_SHARED_LIBS 3 #define TEXT_OFFSET 0 /* * does not yet catch signals sent when the child dies. @@ -192,14 +191,12 @@ void ptrace_disable(struct task_struct *child) long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; - int add = 0; unsigned long __user *datap = (unsigned long __user *)data; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKDATA: pr_debug("ptrace: PEEKDATA\n"); - add = MAX_SHARED_LIBS * 4; /* space between text and data */ /* fall through */ case PTRACE_PEEKTEXT: /* read word at location addr. */ { @@ -207,39 +204,38 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int copied; ret = -EIO; - pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add, - sizeof(data)); - if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0) + pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %ld\n", addr, sizeof(data)); + if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0) break; pr_debug("ptrace: user address is valid\n"); #if L1_CODE_LENGTH != 0 - if (addr + add >= L1_CODE_START - && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { - safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp)); + if (addr >= L1_CODE_START + && addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { + safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); } else #endif #if L1_DATA_A_LENGTH != 0 - if (addr + add >= L1_DATA_A_START - && addr + add + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) { - memcpy(&tmp, (const void *)(addr + add), sizeof(tmp)); + if (addr >= L1_DATA_A_START + && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) { + memcpy(&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); } else #endif #if L1_DATA_B_LENGTH != 0 - if (addr + add >= L1_DATA_B_START - && addr + add + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) { - memcpy(&tmp, (const void *)(addr + add), sizeof(tmp)); + if (addr >= L1_DATA_B_START + && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) { + memcpy(&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); } else #endif - if (addr + add >= FIXED_CODE_START - && addr + add + sizeof(tmp) <= FIXED_CODE_END) { - memcpy(&tmp, (const void *)(addr + add), sizeof(tmp)); + if (addr >= FIXED_CODE_START + && addr + sizeof(tmp) <= FIXED_CODE_END) { + memcpy(&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); } else - copied = access_process_vm(child, addr + add, &tmp, + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); if (copied != sizeof(tmp)) @@ -291,39 +287,39 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int copied; ret = -EIO; - pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n", - addr, add, sizeof(data), data); - if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0) + pr_debug("ptrace: POKETEXT at addr 0x%08lx + %ld bytes %lx\n", + addr, sizeof(data), data); + if (is_user_addr_valid(child, addr, sizeof(data)) < 0) break; pr_debug("ptrace: user address is valid\n"); #if L1_CODE_LENGTH != 0 - if (addr + add >= L1_CODE_START - && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { - safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data)); + if (addr >= L1_CODE_START + && addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { + safe_dma_memcpy ((void *)(addr), &data, sizeof(data)); copied = sizeof(data); } else #endif #if L1_DATA_A_LENGTH != 0 - if (addr + add >= L1_DATA_A_START - && addr + add + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) { - memcpy((void *)(addr + add), &data, sizeof(data)); + if (addr >= L1_DATA_A_START + && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) { + memcpy((void *)(addr), &data, sizeof(data)); copied = sizeof(data); } else #endif #if L1_DATA_B_LENGTH != 0 - if (addr + add >= L1_DATA_B_START - && addr + add + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) { - memcpy((void *)(addr + add), &data, sizeof(data)); + if (addr >= L1_DATA_B_START + && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) { + memcpy((void *)(addr), &data, sizeof(data)); copied = sizeof(data); } else #endif - if (addr + add >= FIXED_CODE_START - && addr + add + sizeof(data) <= FIXED_CODE_END) { - memcpy((void *)(addr + add), &data, sizeof(data)); + if (addr >= FIXED_CODE_START + && addr + sizeof(data) <= FIXED_CODE_END) { + memcpy((void *)(addr), &data, sizeof(data)); copied = sizeof(data); } else - copied = access_process_vm(child, addr + add, &data, + copied = access_process_vm(child, addr, &data, sizeof(data), 1); pr_debug("ptrace: copied size %d\n", copied); if (copied != sizeof(data)) -- cgit v1.2.3-58-ga151 From d3ab3a62f57f3aaeed5a7e2ef136937ffd16448a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Oct 2008 15:19:50 +0800 Subject: Blackfin arch: ptrace - cleanup debug messages and style Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/ptrace.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 9ce80d05e2c9..b3f4ac792cf1 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -280,7 +280,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKEDATA: - printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n"); + pr_debug("ptrace: PTRACE_PEEKDATA\n"); /* fall through */ case PTRACE_POKETEXT: /* write the word at location addr. */ { @@ -351,7 +351,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) { /* restart after signal. */ long tmp; - pr_debug("ptrace_cont\n"); + pr_debug("ptrace: syscall/cont\n"); ret = -EIO; if (!valid_signal(data)) @@ -365,7 +365,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* make sure the single step bit is not set. */ tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); put_reg(child, PT_SYSCFG, tmp); - pr_debug("before wake_up_process\n"); + pr_debug("ptrace: before wake_up_process\n"); wake_up_process(child); ret = 0; break; @@ -394,7 +394,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) { /* set the trap flag. */ long tmp; - pr_debug("single step\n"); + pr_debug("ptrace: single step\n"); ret = -EIO; if (!valid_signal(data)) break; @@ -411,21 +411,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) } case PTRACE_GETREGS: - { - - /* Get all gp regs from the child. */ - ret = ptrace_getregs(child, datap); - break; - } + /* Get all gp regs from the child. */ + ret = ptrace_getregs(child, datap); + break; case PTRACE_SETREGS: - { - printk(KERN_NOTICE - "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); - /* Set all gp regs in the child. */ - ret = 0; - break; - } + printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); + /* Set all gp regs in the child. */ + ret = 0; + break; + default: ret = ptrace_request(child, request, addr, data); break; @@ -436,7 +431,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) asmlinkage void syscall_trace(void) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) return; -- cgit v1.2.3-58-ga151 From cb4c173d94e90f9d8c7b621d1a8dfc8b741874a2 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Oct 2008 15:21:05 +0800 Subject: Blackfin arch: use existing ptrace_disable() func to clear TRACE_BITS and create the opposite ptrace_enable() Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/ptrace.c | 87 ++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 50 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index b3f4ac792cf1..e8172eece047 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -175,6 +175,13 @@ static inline int is_user_addr_valid(struct task_struct *child, return -EIO; } +void ptrace_enable(struct task_struct *child) +{ + unsigned long tmp; + tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS); + put_reg(child, PT_SYSCFG, tmp); +} + /* * Called by kernel/ptrace.c when detaching.. * @@ -347,29 +354,22 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: - { /* restart after signal. */ - long tmp; - - pr_debug("ptrace: syscall/cont\n"); + case PTRACE_CONT: /* restart after signal. */ + pr_debug("ptrace: syscall/cont\n"); - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - - child->exit_code = data; - /* make sure the single step bit is not set. */ - tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); - put_reg(child, PT_SYSCFG, tmp); - pr_debug("ptrace: before wake_up_process\n"); - wake_up_process(child); - ret = 0; + ret = -EIO; + if (!valid_signal(data)) break; - } + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + ptrace_disable(child); + pr_debug("ptrace: before wake_up_process\n"); + wake_up_process(child); + ret = 0; + break; /* * make the child exit. Best I can do is send it a sigkill. @@ -377,38 +377,25 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) * exit. */ case PTRACE_KILL: - { - long tmp; - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS); - put_reg(child, PT_SYSCFG, tmp); - wake_up_process(child); + ret = 0; + if (child->exit_state == EXIT_ZOMBIE) /* already dead */ break; - } - - case PTRACE_SINGLESTEP: - { /* set the trap flag. */ - long tmp; - - pr_debug("ptrace: single step\n"); - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - - tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS); - put_reg(child, PT_SYSCFG, tmp); + child->exit_code = SIGKILL; + ptrace_disable(child); + wake_up_process(child); + break; - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; + case PTRACE_SINGLESTEP: /* set the trap flag. */ + pr_debug("ptrace: single step\n"); + ret = -EIO; + if (!valid_signal(data)) break; - } + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + ptrace_enable(child); + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; case PTRACE_GETREGS: /* Get all gp regs from the child. */ -- cgit v1.2.3-58-ga151 From f5a817e3f707759882e423060badd2f2e52b66a4 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Oct 2008 15:22:56 +0800 Subject: Blackfin arch: ptrace - make sure PT_ORIG_R0 and PT_ORIG_P0 offsets are declared Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/ptrace.h | 2 ++ arch/blackfin/kernel/asm-offsets.c | 1 + 2 files changed, 3 insertions(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h index a45a80e54adc..e3f086dc7268 100644 --- a/arch/blackfin/include/asm/ptrace.h +++ b/arch/blackfin/include/asm/ptrace.h @@ -158,6 +158,8 @@ extern void show_regs(struct pt_regs *); #define PT_SEQSTAT 8 #define PT_IPEND 4 +#define PT_ORIG_R0 208 +#define PT_ORIG_P0 212 #define PT_SYSCFG 216 #define PT_TEXT_ADDR 220 #define PT_TEXT_END_ADDR 224 diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c index 881afe9082c7..9bb85dd5ccb3 100644 --- a/arch/blackfin/kernel/asm-offsets.c +++ b/arch/blackfin/kernel/asm-offsets.c @@ -60,6 +60,7 @@ int main(void) DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE); /* offsets into the pt_regs */ + DEFINE(PT_ORIG_R0, offsetof(struct pt_regs, orig_r0)); DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0)); DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc)); DEFINE(PT_R0, offsetof(struct pt_regs, r0)); -- cgit v1.2.3-58-ga151 From 55f2feae3a1e075d9b4b0e73a6024f3e25717878 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Thu, 9 Oct 2008 15:37:47 +0800 Subject: Blackfin arch: correct icache size in show_cpuinfo(), let c_start() return proper pointer Signed-off-by: Graf Yang Signed-off-by: Bryan Wu --- arch/blackfin/kernel/setup.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index ea4f60978c66..e9054e0b4555 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -1000,7 +1000,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) "cpu family\t: 0x%x\n" "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n" "stepping\t: %d\n", - 0, + *(unsigned int *)v, vendor, (bfin_read_CHIPID() & CHIPID_FAMILY), cpu, cclk/1000000, sclk/1000000, @@ -1048,7 +1048,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if ((bfin_read_DMEM_CONTROL() & (ENDCPLB | DMC_ENABLE)) != (ENDCPLB | DMC_ENABLE)) dcache_size = 0; - if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) == (IMC | ENICPLB)) + if ((bfin_read_IMEM_CONTROL() & (IMC | ENICPLB)) != (IMC | ENICPLB)) icache_size = 0; seq_printf(m, "cache size\t: %d KB(L1 icache) " @@ -1137,12 +1137,18 @@ static int show_cpuinfo(struct seq_file *m, void *v) static void *c_start(struct seq_file *m, loff_t *pos) { - return *pos < NR_CPUS ? ((void *)0x12345678) : NULL; + if (*pos == 0) + *pos = first_cpu(cpu_online_map); + if (*pos >= num_online_cpus()) + return NULL; + + return pos; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { - ++*pos; + *pos = next_cpu(*pos, cpu_online_map); + return c_start(m, pos); } -- cgit v1.2.3-58-ga151 From 1d5ff7e27d2ca30cd3f61afd353b03dd67330818 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 9 Oct 2008 17:06:32 +0800 Subject: Blackfin arch: Fix bug - HW Errors never recover on BF548 The kernel does not properly clear the EBIU Error Master (EBIU_ERRMST) Register on BF548, which causes the kernel to panic. We need to make sure that we clear the EBIU_ERRMST (necessary on BF54x) Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/kernel/traps.c | 15 +++++++++++++-- arch/blackfin/mach-common/interrupt.S | 9 +++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 1a3c4daf557a..709c247b7016 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -1025,8 +1025,19 @@ void show_regs(struct pt_regs *fp) printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", (long)fp->seqstat, fp->ipend, fp->syscfg); - printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n", - (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14); + if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) { + printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n", + (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14); +#ifdef EBIU_ERRMST + /* If the error was from the EBIU, print it out */ + if (bfin_read_EBIU_ERRMST() & CORE_ERROR) { + printk(KERN_NOTICE " EBIU Error Reason : 0x%04x\n", + bfin_read_EBIU_ERRMST()); + printk(KERN_NOTICE " EBIU Error Address : 0x%08x\n", + bfin_read_EBIU_ERRADD()); + } +#endif + } printk(KERN_NOTICE " EXCAUSE : 0x%lx\n", fp->seqstat & SEQSTAT_EXCAUSE); for (i = 6; i <= 15 ; i++) { diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 647f0f522910..4a2ec7a9675a 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -179,7 +179,16 @@ ENTRY(_evt_ivhw) call _trap_c; SP += 12; +#ifdef EBIU_ERRMST + /* make sure EBIU_ERRMST is clear */ + p0.l = LO(EBIU_ERRMST); + p0.h = HI(EBIU_ERRMST); + r0.l = (CORE_ERROR | CORE_MERROR); + w[p0] = r0.l; +#endif + call _ret_from_exception; + .Lcommon_restore_all_sys: RESTORE_ALL_SYS rti; -- cgit v1.2.3-58-ga151 From 0c0497c257c12c9ecb8825490a339bfce8a0532f Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 9 Oct 2008 17:32:28 +0800 Subject: Blackfin arch: Move all the silicon rev handling to one place Move all the silicon rev handling to one place (Kconfig) and make sure we warn if you are running on silicon that has not been tested on Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig | 13 +++++++++++++ arch/blackfin/kernel/setup.c | 3 ++- arch/blackfin/mach-bf527/include/mach/bf527.h | 2 -- arch/blackfin/mach-bf533/include/mach/bf533.h | 2 -- arch/blackfin/mach-bf537/include/mach/bf537.h | 2 -- arch/blackfin/mach-bf548/include/mach/bf548.h | 2 -- arch/blackfin/mach-bf561/include/mach/bf561.h | 2 -- 7 files changed, 15 insertions(+), 11 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 10c97efbd91f..8102c79aaa94 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -166,6 +166,19 @@ config BF561 endchoice +config BF_REV_MIN + int + default 0 if (BF52x || BF54x) + default 2 if (BF537 || BF536 || BF534) + default 3 if (BF561 ||BF533 || BF532 || BF531) + +config BF_REV_MAX + int + default 2 if (BF52x || BF54x) + default 3 if (BF537 || BF536 || BF534) + default 5 if (BF561) + default 6 if (BF533 || BF532 || BF531) + choice prompt "Silicon Rev" default BF_REV_0_1 if (BF52x || BF54x) diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index e9054e0b4555..4267523912bd 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -821,9 +821,10 @@ void __init setup_arch(char **cmdline_p) printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n", bfin_compiled_revid(), bfin_revid()); } - if (bfin_revid() < SUPPORTED_REVID) + if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX) printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n", CPU, bfin_revid()); + printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n", diff --git a/arch/blackfin/mach-bf527/include/mach/bf527.h b/arch/blackfin/mach-bf527/include/mach/bf527.h index 056eb4b9cd25..330041fde546 100644 --- a/arch/blackfin/mach-bf527/include/mach/bf527.h +++ b/arch/blackfin/mach-bf527/include/mach/bf527.h @@ -30,8 +30,6 @@ #ifndef __MACH_BF527_H__ #define __MACH_BF527_H__ -#define SUPPORTED_REVID 2 - #define OFFSET_(x) ((x) & 0x0000FFFF) /*some misc defines*/ diff --git a/arch/blackfin/mach-bf533/include/mach/bf533.h b/arch/blackfin/mach-bf533/include/mach/bf533.h index 12a416931991..949801112303 100644 --- a/arch/blackfin/mach-bf533/include/mach/bf533.h +++ b/arch/blackfin/mach-bf533/include/mach/bf533.h @@ -30,8 +30,6 @@ #ifndef __MACH_BF533_H__ #define __MACH_BF533_H__ -#define SUPPORTED_REVID 2 - #define OFFSET_(x) ((x) & 0x0000FFFF) /*some misc defines*/ diff --git a/arch/blackfin/mach-bf537/include/mach/bf537.h b/arch/blackfin/mach-bf537/include/mach/bf537.h index cfe2a221112e..7a047e04e383 100644 --- a/arch/blackfin/mach-bf537/include/mach/bf537.h +++ b/arch/blackfin/mach-bf537/include/mach/bf537.h @@ -30,8 +30,6 @@ #ifndef __MACH_BF537_H__ #define __MACH_BF537_H__ -#define SUPPORTED_REVID 2 - /* Masks for generic ERROR IRQ demultiplexing used in int-priority-sc.c */ #define SPI_ERR_MASK (TXCOL | RBSY | MODF | TXE) /* SPI_STAT */ diff --git a/arch/blackfin/mach-bf548/include/mach/bf548.h b/arch/blackfin/mach-bf548/include/mach/bf548.h index e748588e8930..14f8a7b84544 100644 --- a/arch/blackfin/mach-bf548/include/mach/bf548.h +++ b/arch/blackfin/mach-bf548/include/mach/bf548.h @@ -30,8 +30,6 @@ #ifndef __MACH_BF548_H__ #define __MACH_BF548_H__ -#define SUPPORTED_REVID 0 - #define OFFSET_(x) ((x) & 0x0000FFFF) /*some misc defines*/ diff --git a/arch/blackfin/mach-bf561/include/mach/bf561.h b/arch/blackfin/mach-bf561/include/mach/bf561.h index 3ef9e5f36136..7787caad3555 100644 --- a/arch/blackfin/mach-bf561/include/mach/bf561.h +++ b/arch/blackfin/mach-bf561/include/mach/bf561.h @@ -30,8 +30,6 @@ #ifndef __MACH_BF561_H__ #define __MACH_BF561_H__ -#define SUPPORTED_REVID 0x3 - #define OFFSET_(x) ((x) & 0x0000FFFF) /*some misc defines*/ -- cgit v1.2.3-58-ga151 From d207a8c7681f14302e9e80ef5b8202abe39060b5 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 10 Oct 2008 17:26:57 +0800 Subject: Blackfin arch: ptrace - fix off-by-one check on end of memory regions Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/ptrace.c | 50 ++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index e8172eece047..7e1f762b6700 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -161,15 +161,15 @@ static inline int is_user_addr_valid(struct task_struct *child, struct sram_list_struct *sraml; for (vml = child->mm->context.vmlist; vml; vml = vml->next) - if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end) + if (start >= vml->vma->vm_start && start + len < vml->vma->vm_end) return 0; for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next) if (start >= (unsigned long)sraml->addr - && start + len <= (unsigned long)sraml->addr + sraml->length) + && start + len < (unsigned long)sraml->addr + sraml->length) return 0; - if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END) + if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END) return 0; return -EIO; @@ -216,34 +216,30 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; pr_debug("ptrace: user address is valid\n"); -#if L1_CODE_LENGTH != 0 - if (addr >= L1_CODE_START + if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START && addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); - } else -#endif -#if L1_DATA_A_LENGTH != 0 - if (addr >= L1_DATA_A_START + + } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) { memcpy(&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); - } else -#endif -#if L1_DATA_B_LENGTH != 0 - if (addr >= L1_DATA_B_START + + } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) { memcpy(&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); - } else -#endif - if (addr >= FIXED_CODE_START + + } else if (addr >= FIXED_CODE_START && addr + sizeof(tmp) <= FIXED_CODE_END) { memcpy(&tmp, (const void *)(addr), sizeof(tmp)); copied = sizeof(tmp); + } else copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); if (copied != sizeof(tmp)) break; @@ -300,34 +296,30 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; pr_debug("ptrace: user address is valid\n"); -#if L1_CODE_LENGTH != 0 - if (addr >= L1_CODE_START + if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START && addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { safe_dma_memcpy ((void *)(addr), &data, sizeof(data)); copied = sizeof(data); - } else -#endif -#if L1_DATA_A_LENGTH != 0 - if (addr >= L1_DATA_A_START + + } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) { memcpy((void *)(addr), &data, sizeof(data)); copied = sizeof(data); - } else -#endif -#if L1_DATA_B_LENGTH != 0 - if (addr >= L1_DATA_B_START + + } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) { memcpy((void *)(addr), &data, sizeof(data)); copied = sizeof(data); - } else -#endif - if (addr >= FIXED_CODE_START + + } else if (addr >= FIXED_CODE_START && addr + sizeof(data) <= FIXED_CODE_END) { memcpy((void *)(addr), &data, sizeof(data)); copied = sizeof(data); + } else copied = access_process_vm(child, addr, &data, sizeof(data), 1); + pr_debug("ptrace: copied size %d\n", copied); if (copied != sizeof(data)) break; -- cgit v1.2.3-58-ga151 From 3c08f1d122627c9559fb03a11f52ea37f960b61e Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 10 Oct 2008 17:12:51 +0800 Subject: Blackfin arch: have is_user_addr_valid() check for overflows (like when address is -1) Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/ptrace.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 7e1f762b6700..140bf00e9974 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -160,6 +160,10 @@ static inline int is_user_addr_valid(struct task_struct *child, struct vm_list_struct *vml; struct sram_list_struct *sraml; + /* overflow */ + if (start + len < start) + return -EIO; + for (vml = child->mm->context.vmlist; vml; vml = vml->next) if (start >= vml->vma->vm_start && start + len < vml->vma->vm_end) return 0; -- cgit v1.2.3-58-ga151 From a88c71e4367aada2065c5e247477c891d2ca952f Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 10 Oct 2008 17:37:52 +0800 Subject: Blackfin arch: emulate a TTY over the EMUDAT/JTAG interface Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/kernel/early_printk.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c index 60f67f90fe35..1f4e3d2e0901 100644 --- a/arch/blackfin/kernel/early_printk.c +++ b/arch/blackfin/kernel/early_printk.c @@ -35,6 +35,9 @@ extern struct console *bfin_earlyserial_init(unsigned int port, unsigned int cflag); #endif +#ifdef CONFIG_BFIN_JTAG_COMM +extern struct console *bfin_jc_early_init(void); +#endif static struct console *early_console; @@ -142,6 +145,15 @@ int __init setup_early_printk(char *buf) early_console = earlyserial_init(buf); } #endif + +#ifdef CONFIG_BFIN_JTAG_COMM + /* Check for Blackfin JTAG */ + if (!strncmp(buf, "jtag", 4)) { + buf += 4; + early_console = bfin_jc_early_init(); + } +#endif + #ifdef CONFIG_FB /* TODO: add framebuffer console support */ #endif -- cgit v1.2.3-58-ga151 From 9f06c38fb230720371397a57faa24aa6e31b2c87 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Fri, 10 Oct 2008 18:13:21 +0800 Subject: Blackfin arch: Add optional verbose debug Add optional verbose debug - which when turned off, quiets down userspace errors. Saves ~8k of code/data for production systems Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/Kconfig.debug | 13 +++ arch/blackfin/kernel/traps.c | 230 ++++++++++++++++++++++++------------------- 2 files changed, 143 insertions(+), 100 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index f08aea4fc5eb..3ad25983ec97 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -5,6 +5,19 @@ source "lib/Kconfig.debug" config HAVE_ARCH_KGDB def_bool y +config DEBUG_VERBOSE + bool "Verbose fault messages" + default y + select PRINTK + help + When a program crashes due to an exception, or the kernel detects + an internal error, the kernel can print a not so brief message + explaining what the problem was. This debugging information is + useful to developers and kernel hackers when tracking down problems, + but mostly meaningless to other people. This is always helpful for + debugging but serves no purpose on a production system. + Most people should say N here. + config DEBUG_MMRS bool "Generate Blackfin MMR tree" select DEBUG_FS diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 709c247b7016..1aa2c788e228 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -58,6 +58,15 @@ # define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0) #endif + +#ifdef CONFIG_VERBOSE_DEBUG +#define verbose_printk(fmt, arg...) \ + printk(fmt, ##arg) +#else +#define verbose_printk(fmt, arg...) \ + ({ if (0) printk(fmt, ##arg); 0; }) +#endif + /* Initiate the event table handler */ void __init trap_init(void) { @@ -78,6 +87,7 @@ unsigned long saved_retx, saved_seqstat, static void decode_address(char *buf, unsigned long address) { +#ifdef CONFIG_DEBUG_VERBOSE struct vm_list_struct *vml; struct task_struct *p; struct mm_struct *mm; @@ -185,12 +195,16 @@ static void decode_address(char *buf, unsigned long address) done: write_unlock_irqrestore(&tasklist_lock, flags); +#else + sprintf(buf, " "); +#endif } asmlinkage void double_fault_c(struct pt_regs *fp) { console_verbose(); oops_in_progress = 1; +#ifdef CONFIG_DEBUG_VERBOSE printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { @@ -213,6 +227,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp) dump_bfin_mem(fp); show_regs(fp); } +#endif panic("Double Fault - unrecoverable event\n"); } @@ -288,7 +303,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_EXCPT03: info.si_code = SEGV_STACKFLOW; sig = SIGSEGV; - printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x02 - KGDB initial connection and break signal trap */ @@ -317,7 +332,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_EXCPT04 ... VEC_EXCPT15: info.si_code = ILL_ILLPARAOP; sig = SIGILL; - printk(KERN_NOTICE EXC_0x04(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x10 HW Single step, handled here */ @@ -334,7 +349,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_OVFLOW: info.si_code = TRAP_TRACEFLOW; sig = SIGTRAP; - printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x12 - Reserved, Caught by default */ @@ -356,35 +371,35 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_UNDEF_I: info.si_code = ILL_ILLOPC; sig = SIGILL; - printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x22 - Illegal Instruction Combination, handled here */ case VEC_ILGAL_I: info.si_code = ILL_ILLPARAOP; sig = SIGILL; - printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x23 - Data CPLB protection violation, handled here */ case VEC_CPLB_VL: info.si_code = ILL_CPLB_VI; sig = SIGBUS; - printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x24 - Data access misaligned, handled here */ case VEC_MISALI_D: info.si_code = BUS_ADRALN; sig = SIGBUS; - printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x25 - Unrecoverable Event, handled here */ case VEC_UNCOV: info.si_code = ILL_ILLEXCPT; sig = SIGILL; - printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr, @@ -392,7 +407,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_CPLB_M: info.si_code = BUS_ADRALN; sig = SIGBUS; - printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE)); break; /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */ case VEC_CPLB_MHIT: @@ -400,10 +415,10 @@ asmlinkage void trap_c(struct pt_regs *fp) sig = SIGSEGV; #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO if (saved_dcplb_fault_addr < FIXED_CODE_START) - printk(KERN_NOTICE "NULL pointer access\n"); + verbose_printk(KERN_NOTICE "NULL pointer access\n"); else #endif - printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x28 - Emulation Watchpoint, handled here */ @@ -422,7 +437,7 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */ info.si_code = BUS_OPFETCH; sig = SIGBUS; - printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n"); + verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n"); CHK_DEBUGGER_TRAP_MAYBE(); break; #else @@ -432,21 +447,21 @@ asmlinkage void trap_c(struct pt_regs *fp) case VEC_MISALI_I: info.si_code = BUS_ADRALN; sig = SIGBUS; - printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2B - Instruction CPLB protection violation, handled here */ case VEC_CPLB_I_VL: info.si_code = ILL_CPLB_VI; sig = SIGBUS; - printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */ case VEC_CPLB_I_M: info.si_code = ILL_CPLB_MISS; sig = SIGBUS; - printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE)); break; /* 0x2D - Instruction CPLB Multiple Hits, handled here */ case VEC_CPLB_I_MHIT: @@ -454,17 +469,17 @@ asmlinkage void trap_c(struct pt_regs *fp) sig = SIGSEGV; #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO if (saved_icplb_fault_addr < FIXED_CODE_START) - printk(KERN_NOTICE "Jump to NULL address\n"); + verbose_printk(KERN_NOTICE "Jump to NULL address\n"); else #endif - printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2E - Illegal use of Supervisor Resource, handled here */ case VEC_ILL_RES: info.si_code = ILL_PRVOPC; sig = SIGILL; - printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); + verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE)); CHK_DEBUGGER_TRAP_MAYBE(); break; /* 0x2F - Reserved, Caught by default */ @@ -492,17 +507,17 @@ asmlinkage void trap_c(struct pt_regs *fp) case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): info.si_code = BUS_ADRALN; sig = SIGBUS; - printk(KERN_NOTICE HWC_x2(KERN_NOTICE)); + verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE)); break; /* External Memory Addressing Error */ case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): info.si_code = BUS_ADRERR; sig = SIGBUS; - printk(KERN_NOTICE HWC_x3(KERN_NOTICE)); + verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE)); break; /* Performance Monitor Overflow */ case (SEQSTAT_HWERRCAUSE_PERF_FLOW): - printk(KERN_NOTICE HWC_x12(KERN_NOTICE)); + verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE)); break; /* RAISE 5 instruction */ case (SEQSTAT_HWERRCAUSE_RAISE_5): @@ -522,7 +537,7 @@ asmlinkage void trap_c(struct pt_regs *fp) oops_in_progress = 1; info.si_code = ILL_ILLPARAOP; sig = SIGILL; - printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", + verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n", (fp->seqstat & SEQSTAT_EXCAUSE)); CHK_DEBUGGER_TRAP_MAYBE(); break; @@ -531,7 +546,6 @@ asmlinkage void trap_c(struct pt_regs *fp) BUG_ON(sig == 0); if (sig != SIGTRAP) { - unsigned long *stack; dump_bfin_process(fp); dump_bfin_mem(fp); show_regs(fp); @@ -539,7 +553,7 @@ asmlinkage void trap_c(struct pt_regs *fp) /* Print out the trace buffer if it makes sense */ #ifndef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE if (trapnr == VEC_CPLB_I_M || trapnr == VEC_CPLB_M) - printk(KERN_NOTICE "No trace since you do not have " + verbose_printk(KERN_NOTICE "No trace since you do not have " "CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE enabled\n" KERN_NOTICE "\n"); else @@ -548,20 +562,22 @@ asmlinkage void trap_c(struct pt_regs *fp) if (oops_in_progress) { /* Dump the current kernel stack */ - printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n"); + verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "Kernel Stack\n"); show_stack(current, NULL); - print_modules(); #ifndef CONFIG_ACCESS_CHECK - printk(KERN_EMERG "Please turn on " + verbose_printk(KERN_EMERG "Please turn on " "CONFIG_ACCESS_CHECK\n"); #endif panic("Kernel exception"); } else { +#ifdef CONFIG_VERBOSE_DEBUG + unsigned long *stack; /* Dump the user space stack */ stack = (unsigned long *)rdusp(); - printk(KERN_NOTICE "Userspace Stack\n"); + verbose_printk(KERN_NOTICE "Userspace Stack\n"); show_stack(NULL, stack); +#endif } } @@ -582,7 +598,7 @@ asmlinkage void trap_c(struct pt_regs *fp) * Similar to get_user, do some address checking, then dereference * Return true on sucess, false on bad address */ -bool get_instruction(unsigned short *val, unsigned short *address) +static bool get_instruction(unsigned short *val, unsigned short *address) { unsigned long addr; @@ -643,45 +659,48 @@ bool get_instruction(unsigned short *val, unsigned short *address) * These are the normal instructions which cause change of flow, which * would be at the source of the trace buffer */ -void decode_instruction(unsigned short *address) +#ifdef CONFIG_DEBUG_VERBOSE +static void decode_instruction(unsigned short *address) { unsigned short opcode; if (get_instruction(&opcode, address)) { if (opcode == 0x0010) - printk("RTS"); + verbose_printk("RTS"); else if (opcode == 0x0011) - printk("RTI"); + verbose_printk("RTI"); else if (opcode == 0x0012) - printk("RTX"); + verbose_printk("RTX"); else if (opcode >= 0x0050 && opcode <= 0x0057) - printk("JUMP (P%i)", opcode & 7); + verbose_printk("JUMP (P%i)", opcode & 7); else if (opcode >= 0x0060 && opcode <= 0x0067) - printk("CALL (P%i)", opcode & 7); + verbose_printk("CALL (P%i)", opcode & 7); else if (opcode >= 0x0070 && opcode <= 0x0077) - printk("CALL (PC+P%i)", opcode & 7); + verbose_printk("CALL (PC+P%i)", opcode & 7); else if (opcode >= 0x0080 && opcode <= 0x0087) - printk("JUMP (PC+P%i)", opcode & 7); + verbose_printk("JUMP (PC+P%i)", opcode & 7); else if ((opcode >= 0x1000 && opcode <= 0x13FF) || (opcode >= 0x1800 && opcode <= 0x1BFF)) - printk("IF !CC JUMP"); + verbose_printk("IF !CC JUMP"); else if ((opcode >= 0x1400 && opcode <= 0x17ff) || (opcode >= 0x1c00 && opcode <= 0x1fff)) - printk("IF CC JUMP"); + verbose_printk("IF CC JUMP"); else if (opcode >= 0x2000 && opcode <= 0x2fff) - printk("JUMP.S"); + verbose_printk("JUMP.S"); else if (opcode >= 0xe080 && opcode <= 0xe0ff) - printk("LSETUP"); + verbose_printk("LSETUP"); else if (opcode >= 0xe200 && opcode <= 0xe2ff) - printk("JUMP.L"); + verbose_printk("JUMP.L"); else if (opcode >= 0xe300 && opcode <= 0xe3ff) - printk("CALL pcrel"); + verbose_printk("CALL pcrel"); else - printk("0x%04x", opcode); + verbose_printk("0x%04x", opcode); } } +#endif void dump_bfin_trace_buffer(void) { +#ifdef CONFIG_DEBUG_VERBOSE #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON int tflags, i = 0; char buf[150]; @@ -737,6 +756,7 @@ void dump_bfin_trace_buffer(void) trace_buffer_restore(tflags); #endif +#endif } EXPORT_SYMBOL(dump_bfin_trace_buffer); @@ -744,7 +764,7 @@ EXPORT_SYMBOL(dump_bfin_trace_buffer); * Checks to see if the address pointed to is either a * 16-bit CALL instruction, or a 32-bit CALL instruction */ -bool is_bfin_call(unsigned short *addr) +static bool is_bfin_call(unsigned short *addr) { unsigned short opcode = 0, *ins_addr; ins_addr = (unsigned short *)addr; @@ -766,8 +786,10 @@ bool is_bfin_call(unsigned short *addr) return false; } + void show_stack(struct task_struct *task, unsigned long *stack) { +#ifdef CONFIG_PRINTK unsigned int *addr, *endstack, *fp = 0, *frame; unsigned short *ins_addr; char buf[150]; @@ -792,8 +814,10 @@ void show_stack(struct task_struct *task, unsigned long *stack) } else endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); + printk(KERN_NOTICE "Stack info:\n"); decode_address(buf, (unsigned int)stack); - printk(KERN_NOTICE "Stack info:\n" KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); + printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); + addr = (unsigned int *)((unsigned int)stack & ~0x3F); /* First thing is to look for a frame pointer */ @@ -884,7 +908,7 @@ void show_stack(struct task_struct *task, unsigned long *stack) if (!j) printk("\n"); } - +#endif } void dump_stack(void) @@ -902,38 +926,39 @@ EXPORT_SYMBOL(dump_stack); void dump_bfin_process(struct pt_regs *fp) { +#ifdef CONFIG_DEBUG_VERBOSE /* We should be able to look at fp->ipend, but we don't push it on the * stack all the time, so do this until we fix that */ unsigned int context = bfin_read_IPEND(); if (oops_in_progress) - printk(KERN_EMERG "Kernel OOPS in progress\n"); + verbose_printk(KERN_EMERG "Kernel OOPS in progress\n"); if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) - printk(KERN_NOTICE "HW Error context\n"); + verbose_printk(KERN_NOTICE "HW Error context\n"); else if (context & 0x0020) - printk(KERN_NOTICE "Deferred Exception context\n"); + verbose_printk(KERN_NOTICE "Deferred Exception context\n"); else if (context & 0x3FC0) - printk(KERN_NOTICE "Interrupt context\n"); + verbose_printk(KERN_NOTICE "Interrupt context\n"); else if (context & 0x4000) - printk(KERN_NOTICE "Deferred Interrupt context\n"); + verbose_printk(KERN_NOTICE "Deferred Interrupt context\n"); else if (context & 0x8000) - printk(KERN_NOTICE "Kernel process context\n"); + verbose_printk(KERN_NOTICE "Kernel process context\n"); /* Because we are crashing, and pointers could be bad, we check things * pretty closely before we use them */ if ((unsigned long)current >= FIXED_CODE_START && !((unsigned long)current & 0x3) && current->pid) { - printk(KERN_NOTICE "CURRENT PROCESS:\n"); + verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n"); if (current->comm >= (char *)FIXED_CODE_START) - printk(KERN_NOTICE "COMM=%s PID=%d\n", + verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n", current->comm, current->pid); else - printk(KERN_NOTICE "COMM= invalid\n"); + verbose_printk(KERN_NOTICE "COMM= invalid\n"); if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START) - printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" + verbose_printk(KERN_NOTICE "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n" KERN_NOTICE " BSS = 0x%p-0x%p USER-STACK = 0x%p\n" KERN_NOTICE "\n", (void *)current->mm->start_code, @@ -944,26 +969,28 @@ void dump_bfin_process(struct pt_regs *fp) (void *)current->mm->brk, (void *)current->mm->start_stack); else - printk(KERN_NOTICE "invalid mm\n"); + verbose_printk(KERN_NOTICE "invalid mm\n"); } else - printk(KERN_NOTICE "\n" KERN_NOTICE + verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "No Valid process in current context\n"); +#endif } void dump_bfin_mem(struct pt_regs *fp) { +#ifdef CONFIG_DEBUG_VERBOSE unsigned short *addr, *erraddr, val = 0, err = 0; char sti = 0, buf[6]; erraddr = (void *)fp->pc; - printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr); + verbose_printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr); for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10; addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10; addr++) { if (!((unsigned long)addr & 0xF)) - printk("\n" KERN_NOTICE "0x%p: ", addr); + verbose_printk("\n" KERN_NOTICE "0x%p: ", addr); if (!get_instruction(&val, addr)) { val = 0; @@ -972,10 +999,10 @@ void dump_bfin_mem(struct pt_regs *fp) sprintf(buf, "%04x", val); if (addr == erraddr) { - printk("[%s]", buf); + verbose_printk("[%s]", buf); err = val; } else - printk(" %s ", buf); + verbose_printk(" %s ", buf); /* Do any previous instructions turn on interrupts? */ if (addr <= erraddr && /* in the past */ @@ -984,14 +1011,14 @@ void dump_bfin_mem(struct pt_regs *fp) sti = 1; } - printk("\n"); + verbose_printk("\n"); /* Hardware error interrupts can be deferred */ if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR && oops_in_progress)){ - printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n"); + verbose_printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n"); #ifndef CONFIG_DEBUG_HWERR - printk(KERN_NOTICE "The remaining message may be meaningless\n" + verbose_printk(KERN_NOTICE "The remaining message may be meaningless\n" KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a" " better idea where it came from\n"); #else @@ -1005,45 +1032,47 @@ void dump_bfin_mem(struct pt_regs *fp) /* And the last RETI points to the current userspace context */ if ((fp + 1)->pc >= current->mm->start_code && (fp + 1)->pc <= current->mm->end_code) { - printk(KERN_NOTICE "It might be better to look around here : \n"); - printk(KERN_NOTICE "-------------------------------------------\n"); + verbose_printk(KERN_NOTICE "It might be better to look around here : \n"); + verbose_printk(KERN_NOTICE "-------------------------------------------\n"); show_regs(fp + 1); - printk(KERN_NOTICE "-------------------------------------------\n"); + verbose_printk(KERN_NOTICE "-------------------------------------------\n"); } } #endif } +#endif } void show_regs(struct pt_regs *fp) { +#ifdef CONFIG_DEBUG_VERBOSE char buf [150]; struct irqaction *action; unsigned int i; unsigned long flags; - printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); - printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", + verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\t\t%s\n", print_tainted()); + verbose_printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", (long)fp->seqstat, fp->ipend, fp->syscfg); if ((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR) { - printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n", + verbose_printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n", (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14); #ifdef EBIU_ERRMST /* If the error was from the EBIU, print it out */ if (bfin_read_EBIU_ERRMST() & CORE_ERROR) { - printk(KERN_NOTICE " EBIU Error Reason : 0x%04x\n", + verbose_printk(KERN_NOTICE " EBIU Error Reason : 0x%04x\n", bfin_read_EBIU_ERRMST()); - printk(KERN_NOTICE " EBIU Error Address : 0x%08x\n", + verbose_printk(KERN_NOTICE " EBIU Error Address : 0x%08x\n", bfin_read_EBIU_ERRADD()); } #endif } - printk(KERN_NOTICE " EXCAUSE : 0x%lx\n", + verbose_printk(KERN_NOTICE " EXCAUSE : 0x%lx\n", fp->seqstat & SEQSTAT_EXCAUSE); for (i = 6; i <= 15 ; i++) { if (fp->ipend & (1 << i)) { decode_address(buf, bfin_read32(EVT0 + 4*i)); - printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf); + verbose_printk(KERN_NOTICE " physical IVG%i asserted : %s\n", i, buf); } } @@ -1056,64 +1085,65 @@ void show_regs(struct pt_regs *fp) goto unlock; decode_address(buf, (unsigned int)action->handler); - printk(KERN_NOTICE " logical irq %3d mapped : %s", i, buf); + verbose_printk(KERN_NOTICE " logical irq %3d mapped : %s", i, buf); for (action = action->next; action; action = action->next) { decode_address(buf, (unsigned int)action->handler); - printk(", %s", buf); + verbose_printk(", %s", buf); } - printk("\n"); + verbose_printk("\n"); unlock: spin_unlock_irqrestore(&irq_desc[i].lock, flags); } } decode_address(buf, fp->rete); - printk(KERN_NOTICE " RETE: %s\n", buf); + verbose_printk(KERN_NOTICE " RETE: %s\n", buf); decode_address(buf, fp->retn); - printk(KERN_NOTICE " RETN: %s\n", buf); + verbose_printk(KERN_NOTICE " RETN: %s\n", buf); decode_address(buf, fp->retx); - printk(KERN_NOTICE " RETX: %s\n", buf); + verbose_printk(KERN_NOTICE " RETX: %s\n", buf); decode_address(buf, fp->rets); - printk(KERN_NOTICE " RETS: %s\n", buf); + verbose_printk(KERN_NOTICE " RETS: %s\n", buf); decode_address(buf, fp->pc); - printk(KERN_NOTICE " PC : %s\n", buf); + verbose_printk(KERN_NOTICE " PC : %s\n", buf); if (((long)fp->seqstat & SEQSTAT_EXCAUSE) && (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) { decode_address(buf, saved_dcplb_fault_addr); - printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); + verbose_printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); decode_address(buf, saved_icplb_fault_addr); - printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); + verbose_printk(KERN_NOTICE "ICPLB_FAULT_ADDR: %s\n", buf); } - printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n"); - printk(KERN_NOTICE " R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", + verbose_printk(KERN_NOTICE "\n" KERN_NOTICE "PROCESSOR STATE:\n"); + verbose_printk(KERN_NOTICE " R0 : %08lx R1 : %08lx R2 : %08lx R3 : %08lx\n", fp->r0, fp->r1, fp->r2, fp->r3); - printk(KERN_NOTICE " R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", + verbose_printk(KERN_NOTICE " R4 : %08lx R5 : %08lx R6 : %08lx R7 : %08lx\n", fp->r4, fp->r5, fp->r6, fp->r7); - printk(KERN_NOTICE " P0 : %08lx P1 : %08lx P2 : %08lx P3 : %08lx\n", + verbose_printk(KERN_NOTICE " P0 : %08lx P1 : %08lx P2 : %08lx P3 : %08lx\n", fp->p0, fp->p1, fp->p2, fp->p3); - printk(KERN_NOTICE " P4 : %08lx P5 : %08lx FP : %08lx SP : %08lx\n", + verbose_printk(KERN_NOTICE " P4 : %08lx P5 : %08lx FP : %08lx SP : %08lx\n", fp->p4, fp->p5, fp->fp, (long)fp); - printk(KERN_NOTICE " LB0: %08lx LT0: %08lx LC0: %08lx\n", + verbose_printk(KERN_NOTICE " LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0, fp->lc0); - printk(KERN_NOTICE " LB1: %08lx LT1: %08lx LC1: %08lx\n", + verbose_printk(KERN_NOTICE " LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1, fp->lc1); - printk(KERN_NOTICE " B0 : %08lx L0 : %08lx M0 : %08lx I0 : %08lx\n", + verbose_printk(KERN_NOTICE " B0 : %08lx L0 : %08lx M0 : %08lx I0 : %08lx\n", fp->b0, fp->l0, fp->m0, fp->i0); - printk(KERN_NOTICE " B1 : %08lx L1 : %08lx M1 : %08lx I1 : %08lx\n", + verbose_printk(KERN_NOTICE " B1 : %08lx L1 : %08lx M1 : %08lx I1 : %08lx\n", fp->b1, fp->l1, fp->m1, fp->i1); - printk(KERN_NOTICE " B2 : %08lx L2 : %08lx M2 : %08lx I2 : %08lx\n", + verbose_printk(KERN_NOTICE " B2 : %08lx L2 : %08lx M2 : %08lx I2 : %08lx\n", fp->b2, fp->l2, fp->m2, fp->i2); - printk(KERN_NOTICE " B3 : %08lx L3 : %08lx M3 : %08lx I3 : %08lx\n", + verbose_printk(KERN_NOTICE " B3 : %08lx L3 : %08lx M3 : %08lx I3 : %08lx\n", fp->b3, fp->l3, fp->m3, fp->i3); - printk(KERN_NOTICE "A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", + verbose_printk(KERN_NOTICE "A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n", fp->a0w, fp->a0x, fp->a1w, fp->a1x); - printk(KERN_NOTICE "USP : %08lx ASTAT: %08lx\n", + verbose_printk(KERN_NOTICE "USP : %08lx ASTAT: %08lx\n", rdusp(), fp->astat); - printk(KERN_NOTICE "\n"); + verbose_printk(KERN_NOTICE "\n"); +#endif } #ifdef CONFIG_SYS_BFIN_SPINLOCK_L1 -- cgit v1.2.3-58-ga151 From e482cad241c0b7108cbc94959307a73d19ba17d5 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Fri, 10 Oct 2008 18:21:45 +0800 Subject: Blackfin arch: print out error/warning if you are running on the incorrect CPU type Signed-off-by: Robin Getz Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/processor.h | 6 ++++ arch/blackfin/kernel/setup.c | 43 +++++++++++++++++---------- arch/blackfin/mach-bf527/include/mach/bf527.h | 19 ++++++++++-- arch/blackfin/mach-bf533/include/mach/bf533.h | 10 +++---- arch/blackfin/mach-bf537/include/mach/bf537.h | 10 +++---- arch/blackfin/mach-bf548/include/mach/bf548.h | 23 +++++++------- arch/blackfin/mach-bf561/include/mach/bf561.h | 6 ++-- 7 files changed, 76 insertions(+), 41 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index 6f3995b119d8..e3e9b41fa8db 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h @@ -134,6 +134,12 @@ static inline uint32_t __pure bfin_revid(void) return revid; } +static inline uint16_t __pure bfin_cpuid(void) +{ + return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12; + +} + static inline uint32_t __pure bfin_compiled_revid(void) { #if defined(CONFIG_BF_REV_0_0) diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 4267523912bd..74370f3707b9 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -813,17 +813,23 @@ void __init setup_arch(char **cmdline_p) printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU); else printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid()); - if (bfin_revid() != bfin_compiled_revid()) { - if (bfin_compiled_revid() == -1) - printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n", - bfin_revid()); - else if (bfin_compiled_revid() != 0xffff) - printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n", - bfin_compiled_revid(), bfin_revid()); + + if (unlikely(CPUID != bfin_cpuid())) + printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n", + CPU, bfin_cpuid(), bfin_revid()); + else { + if (bfin_revid() != bfin_compiled_revid()) { + if (bfin_compiled_revid() == -1) + printk(KERN_ERR "Warning: Compiled for Rev none, but running on Rev %d\n", + bfin_revid()); + else if (bfin_compiled_revid() != 0xffff) + printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n", + bfin_compiled_revid(), bfin_revid()); + } + if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX) + printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n", + CPU, bfin_revid()); } - if (bfin_revid() <= CONFIG_BF_REV_MIN || bfin_revid() > CONFIG_BF_REV_MAX) - printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n", - CPU, bfin_revid()); printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); @@ -997,13 +1003,18 @@ static int show_cpuinfo(struct seq_file *m, void *v) } seq_printf(m, "processor\t: %d\n" - "vendor_id\t: %s\n" - "cpu family\t: 0x%x\n" - "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n" - "stepping\t: %d\n", + "vendor_id\t: %s\n", *(unsigned int *)v, - vendor, - (bfin_read_CHIPID() & CHIPID_FAMILY), + vendor); + + if (CPUID == bfin_cpuid()) + seq_printf(m, "cpu family\t: 0x%04x\n", CPUID); + else + seq_printf(m, "cpu family\t: Compiled for:0x%04x, running on:0x%04x\n", + CPUID, bfin_cpuid()); + + seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n" + "stepping\t: %d\n", cpu, cclk/1000000, sclk/1000000, #ifdef CONFIG_MPU "mpu on", diff --git a/arch/blackfin/mach-bf527/include/mach/bf527.h b/arch/blackfin/mach-bf527/include/mach/bf527.h index 330041fde546..144f08d3f8ea 100644 --- a/arch/blackfin/mach-bf527/include/mach/bf527.h +++ b/arch/blackfin/mach-bf527/include/mach/bf527.h @@ -110,16 +110,31 @@ #ifdef CONFIG_BF527 #define CPU "BF527" +#define CPUID 0x27e4 +#endif +#ifdef CONFIG_BF526 +#define CPU "BF526" +#define CPUID 0x27e4 #endif #ifdef CONFIG_BF525 #define CPU "BF525" +#define CPUID 0x27e4 +#endif +#ifdef CONFIG_BF524 +#define CPU "BF524" +#define CPUID 0x27e4 +#endif +#ifdef CONFIG_BF523 +#define CPU "BF523" +#define CPUID 0x27e4 #endif #ifdef CONFIG_BF522 #define CPU "BF522" +#define CPUID 0x27e4 #endif + #ifndef CPU -#define CPU "UNKNOWN" -#define CPUID 0x0 +#error Unknown CPU type - This kernel doesn't seem to be configured properly #endif #endif /* __MACH_BF527_H__ */ diff --git a/arch/blackfin/mach-bf533/include/mach/bf533.h b/arch/blackfin/mach-bf533/include/mach/bf533.h index 949801112303..dfc8c1ad2d7a 100644 --- a/arch/blackfin/mach-bf533/include/mach/bf533.h +++ b/arch/blackfin/mach-bf533/include/mach/bf533.h @@ -141,19 +141,19 @@ #ifdef CONFIG_BF533 #define CPU "BF533" -#define CPUID 0x027a5000 +#define CPUID 0x27a5 #endif #ifdef CONFIG_BF532 #define CPU "BF532" -#define CPUID 0x0275A000 +#define CPUID 0x275A #endif #ifdef CONFIG_BF531 #define CPU "BF531" -#define CPUID 0x027a5000 +#define CPUID 0x27a5 #endif + #ifndef CPU -#define CPU "UNKNOWN" -#define CPUID 0x0 +#error Unknown CPU type - This kernel doesn't seem to be configured properly #endif #endif /* __MACH_BF533_H__ */ diff --git a/arch/blackfin/mach-bf537/include/mach/bf537.h b/arch/blackfin/mach-bf537/include/mach/bf537.h index 7a047e04e383..24d5c9d42323 100644 --- a/arch/blackfin/mach-bf537/include/mach/bf537.h +++ b/arch/blackfin/mach-bf537/include/mach/bf537.h @@ -121,19 +121,19 @@ #ifdef CONFIG_BF537 #define CPU "BF537" -#define CPUID 0x027c8000 +#define CPUID 0x27c8 #endif #ifdef CONFIG_BF536 #define CPU "BF536" -#define CPUID 0x027c8000 +#define CPUID 0x27c8 #endif #ifdef CONFIG_BF534 #define CPU "BF534" -#define CPUID 0x027c6000 +#define CPUID 0x27c6 #endif + #ifndef CPU -#define CPU "UNKNOWN" -#define CPUID 0x0 +#error Unknown CPU type - This kernel doesn't seem to be configured properly #endif #endif /* __MACH_BF537_H__ */ diff --git a/arch/blackfin/mach-bf548/include/mach/bf548.h b/arch/blackfin/mach-bf548/include/mach/bf548.h index 14f8a7b84544..49f9b403d458 100644 --- a/arch/blackfin/mach-bf548/include/mach/bf548.h +++ b/arch/blackfin/mach-bf548/include/mach/bf548.h @@ -106,20 +106,23 @@ #if defined(CONFIG_BF542) # define CPU "BF542" -# define CPUID 0x027c8000 +# define CPUID 0x27de #elif defined(CONFIG_BF544) -# define CPU "BF544" -# define CPUID 0x027c8000 +# define CPU "BF544" +# define CPUID 0x27de #elif defined(CONFIG_BF547) -# define CPU "BF547" +# define CPU "BF547" +# define CPUID 0x27de #elif defined(CONFIG_BF548) -# define CPU "BF548" -# define CPUID 0x027c6000 +# define CPU "BF548" +# define CPUID 0x27de #elif defined(CONFIG_BF549) -# define CPU "BF549" -#else -# define CPU "UNKNOWN" -# define CPUID 0x0 +# define CPU "BF549" +# define CPUID 0x27de +#endif + +#ifndef CPU +#error Unknown CPU type - This kernel doesn't seem to be configured properly #endif #endif /* __MACH_BF48_H__ */ diff --git a/arch/blackfin/mach-bf561/include/mach/bf561.h b/arch/blackfin/mach-bf561/include/mach/bf561.h index 7787caad3555..18b1b3a223ab 100644 --- a/arch/blackfin/mach-bf561/include/mach/bf561.h +++ b/arch/blackfin/mach-bf561/include/mach/bf561.h @@ -211,11 +211,11 @@ #ifdef CONFIG_BF561 #define CPU "BF561" -#define CPUID 0x027bb000 +#define CPUID 0x27bb #endif + #ifndef CPU -#define CPU "UNKNOWN" -#define CPUID 0x0 +#error Unknown CPU type - This kernel doesn't seem to be configured properly #endif #endif /* __MACH_BF561_H__ */ -- cgit v1.2.3-58-ga151 From 9a6f5ae1f1f3c37aad938a1c82db248a3f95a629 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 10 Oct 2008 18:57:21 +0800 Subject: Blackfin arch: bfin_reset() is an internal reboot function ... everyone should go through machine_restart() Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/bfin-global.h | 1 - arch/blackfin/kernel/reboot.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h index f842ea3bfc19..56dcb0a2d244 100644 --- a/arch/blackfin/include/asm/bfin-global.h +++ b/arch/blackfin/include/asm/bfin-global.h @@ -63,7 +63,6 @@ extern void bfin_dcache_init(void); extern void init_exception_vectors(void); extern void program_IAR(void); -extern void bfin_reset(void); extern asmlinkage void lower_to_irq14(void); extern asmlinkage void bfin_return_from_exception(void); extern asmlinkage void evt14_softirq(void); diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c index b0a8f89cc9b6..d0ead640d992 100644 --- a/arch/blackfin/kernel/reboot.c +++ b/arch/blackfin/kernel/reboot.c @@ -20,7 +20,7 @@ * the core reset. */ __attribute__((l1_text)) -void bfin_reset(void) +static void bfin_reset(void) { /* Wait for completion of "system" events such as cache line * line fills so that we avoid infinite stalls later on as -- cgit v1.2.3-58-ga151 From cdbf4c3c5f4909767c21f47f68f2ee57a8b36b3b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 13 Oct 2008 11:33:43 +0800 Subject: Blackfin arch: use the Blackfin on-chip ROM to do software reset when possible Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/bfrom.h | 85 +++++++++++++++++++++++++++++++++++++++ arch/blackfin/kernel/reboot.c | 10 ++++- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 arch/blackfin/include/asm/bfrom.h (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/bfrom.h b/arch/blackfin/include/asm/bfrom.h new file mode 100644 index 000000000000..cfe8024c3b2f --- /dev/null +++ b/arch/blackfin/include/asm/bfrom.h @@ -0,0 +1,85 @@ +/* Blackfin on-chip ROM API + * + * Copyright 2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __BFROM_H__ +#define __BFROM_H__ + +#include + +/* Possible syscontrol action flags */ +#define SYSCTRL_READ 0x00000000 /* read registers */ +#define SYSCTRL_WRITE 0x00000001 /* write registers */ +#define SYSCTRL_SYSRESET 0x00000002 /* perform system reset */ +#define SYSCTRL_CORERESET 0x00000004 /* perform core reset */ +#define SYSCTRL_SOFTRESET 0x00000006 /* perform core and system reset */ +#define SYSCTRL_VRCTL 0x00000010 /* read/write VR_CTL register */ +#define SYSCTRL_EXTVOLTAGE 0x00000020 /* VDDINT supplied externally */ +#define SYSCTRL_INTVOLTAGE 0x00000000 /* VDDINT generated by on-chip regulator */ +#define SYSCTRL_OTPVOLTAGE 0x00000040 /* For Factory Purposes Only */ +#define SYSCTRL_PLLCTL 0x00000100 /* read/write PLL_CTL register */ +#define SYSCTRL_PLLDIV 0x00000200 /* read/write PLL_DIV register */ +#define SYSCTRL_LOCKCNT 0x00000400 /* read/write PLL_LOCKCNT register */ +#define SYSCTRL_PLLSTAT 0x00000800 /* read/write PLL_STAT register */ + +typedef struct ADI_SYSCTRL_VALUES { + uint16_t uwVrCtl; + uint16_t uwPllCtl; + uint16_t uwPllDiv; + uint16_t uwPllLockCnt; + uint16_t uwPllStat; +} ADI_SYSCTRL_VALUES; + +static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, ADI_SYSCTRL_VALUES *power_settings, void *reserved) = (void *)0xEF000038; + +/* We need a dedicated function since we need to screw with the stack pointer + * when resetting. The on-chip ROM will save/restore registers on the stack + * when doing a system reset, so the stack cannot be outside of the chip. + */ +__attribute__((__noreturn__)) +static inline void bfrom_SoftReset(void *new_stack) +{ + while (1) + __asm__ __volatile__( + "sp = %[stack];" + "jump (%[bfrom_syscontrol]);" + : : [bfrom_syscontrol] "p"(bfrom_SysControl), + "q0"(SYSCTRL_SOFTRESET), + "q1"(0), + "q2"(NULL), + [stack] "p"(new_stack) + ); +} + +/* OTP Functions */ +static uint32_t (* const bfrom_OtpCommand)(uint32_t command, uint32_t value) = (void *)0xEF000018; +static uint32_t (* const bfrom_OtpRead)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001A; +static uint32_t (* const bfrom_OtpWrite)(uint32_t page, uint32_t flags, uint64_t *page_content) = (void *)0xEF00001C; + +/* otp command: defines for "command" */ +#define OTP_INIT 0x00000001 +#define OTP_CLOSE 0x00000002 + +/* otp read/write: defines for "flags" */ +#define OTP_LOWER_HALF 0x00000000 /* select upper/lower 64-bit half (bit 0) */ +#define OTP_UPPER_HALF 0x00000001 +#define OTP_NO_ECC 0x00000010 /* do not use ECC */ +#define OTP_LOCK 0x00000020 /* sets page protection bit for page */ +#define OTP_CHECK_FOR_PREV_WRITE 0x00000080 + +/* Return values for all functions */ +#define OTP_SUCCESS 0x00000000 +#define OTP_MASTER_ERROR 0x001 +#define OTP_WRITE_ERROR 0x003 +#define OTP_READ_ERROR 0x005 +#define OTP_ACC_VIO_ERROR 0x009 +#define OTP_DATA_MULT_ERROR 0x011 +#define OTP_ECC_MULT_ERROR 0x021 +#define OTP_PREV_WR_ERROR 0x041 +#define OTP_DATA_SB_WARN 0x100 +#define OTP_ECC_SB_WARN 0x200 + +#endif diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c index d0ead640d992..ae97ca407b0d 100644 --- a/arch/blackfin/kernel/reboot.c +++ b/arch/blackfin/kernel/reboot.c @@ -10,6 +10,7 @@ #include #include #include +#include /* A system soft reset makes external memory unusable so force * this function into L1. We use the compiler ssync here rather @@ -74,7 +75,14 @@ void machine_restart(char *cmd) { native_machine_restart(cmd); local_irq_disable(); - bfin_reset(); + if (ANOMALY_05000353 || ANOMALY_05000386) + bfin_reset(); + else + /* the bootrom checks to see how it was reset and will + * automatically perform a software reset for us when + * it starts executing boot + */ + asm("raise 1;"); } __attribute__((weak)) -- cgit v1.2.3-58-ga151 From 3094c981f2d567f0a442687ced24a5340aa10b6c Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Fri, 10 Oct 2008 21:22:01 +0800 Subject: Blackfin arch: fix a typo in comments Signed-off-by: Bryan Wu --- arch/blackfin/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 74370f3707b9..7054594831c5 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -411,7 +411,7 @@ static __init void parse_cmdline_early(char *cmdline_p) * [_rambase, _ramstart]: kernel image * [memory_start, memory_end]: dynamic memory managed by kernel * [memory_end, _ramend]: reserved memory - * [meory_mtd_start(memory_end), + * [memory_mtd_start(memory_end), * memory_mtd_start + mtd_size]: rootfs (if any) * [_ramend - DMA_UNCACHED_REGION, * _ramend]: uncached DMA region -- cgit v1.2.3-58-ga151 From 58c35bd31f8b577e03d904c214b55b3d91369a85 Mon Sep 17 00:00:00 2001 From: Vitja Makarov Date: Mon, 13 Oct 2008 15:23:56 +0800 Subject: Blackfin arch: introducing bfin_addr_dcachable This patch introduces bfin_addr_dcachable() predicate, that simply tests is address in cachable region or not. Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/cplbinit.h | 14 ++++++++++++++ arch/blackfin/kernel/setup.c | 1 + 2 files changed, 15 insertions(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/cplbinit.h b/arch/blackfin/include/asm/cplbinit.h index 9d23cd1ff7d9..d179b747ff03 100644 --- a/arch/blackfin/include/asm/cplbinit.h +++ b/arch/blackfin/include/asm/cplbinit.h @@ -92,4 +92,18 @@ extern unsigned long reserved_mem_icache_on; extern void generate_cplb_tables(void); +static inline int bfin_addr_dcachable(unsigned long addr) +{ +#ifdef CONFIG_BFIN_DCACHE + if (addr < (_ramend - DMA_UNCACHED_REGION)) + return 1; +#endif + + if (reserved_mem_dcache_on && + addr >= _ramend && addr < physical_mem_end) + return 1; + + return 0; +} + #endif diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 7054594831c5..7f35d1046cd8 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -42,6 +42,7 @@ EXPORT_SYMBOL(memory_start); EXPORT_SYMBOL(memory_end); EXPORT_SYMBOL(physical_mem_end); EXPORT_SYMBOL(_ramend); +EXPORT_SYMBOL(reserved_mem_dcache_on); #ifdef CONFIG_MTD_UCLINUX unsigned long memory_mtd_end, memory_mtd_start, mtd_size; -- cgit v1.2.3-58-ga151 From e9fae189caae7c1cf306e30f5b67c6d226ed69cf Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 13 Oct 2008 11:35:22 +0800 Subject: Blackfin arch: Fix bogus str_ident check in gpio code Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/kernel/bfin_gpio.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 12710ed180be..6e08f425bb44 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -238,7 +238,7 @@ static void gpio_error(unsigned gpio) static void set_label(unsigned short ident, const char *label) { - if (label && str_ident) { + if (label) { strncpy(str_ident[ident].name, label, RESOURCE_LABEL_SIZE); str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; @@ -247,9 +247,6 @@ static void set_label(unsigned short ident, const char *label) static char *get_label(unsigned short ident) { - if (!str_ident) - return "UNKNOWN"; - return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); } @@ -260,7 +257,7 @@ static int cmp_label(unsigned short ident, const char *label) printk(KERN_ERR "Please provide none-null label\n"); } - if (label && str_ident) + if (label) return strncmp(str_ident[ident].name, label, strlen(label)); else -- cgit v1.2.3-58-ga151