From eae6c0da9df81300895949897c0451423340ac40 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 26 Sep 2006 23:43:40 +0900 Subject: [MIPS] lockdep: fix TRACE_IRQFLAGS_SUPPORT In handle_sys and its variants, we must reload some registers which might be clobbered by trace_hardirqs_on(). Also we must make sure trace_hardirqs_on() called in kernel level (not exception level). Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- include/asm-mips/irqflags.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'include') diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h index 43ca09a3a3d0..46bf5de5ac72 100644 --- a/include/asm-mips/irqflags.h +++ b/include/asm-mips/irqflags.h @@ -213,12 +213,37 @@ static inline int raw_irqs_disabled_flags(unsigned long flags) * Do the CPU's IRQ-state tracing from assembly code. */ #ifdef CONFIG_TRACE_IRQFLAGS +/* Reload some registers clobbered by trace_hardirqs_on */ +#ifdef CONFIG_64BIT +# define TRACE_IRQS_RELOAD_REGS \ + LONG_L $11, PT_R11(sp); \ + LONG_L $10, PT_R10(sp); \ + LONG_L $9, PT_R9(sp); \ + LONG_L $8, PT_R8(sp); \ + LONG_L $7, PT_R7(sp); \ + LONG_L $6, PT_R6(sp); \ + LONG_L $5, PT_R5(sp); \ + LONG_L $4, PT_R4(sp); \ + LONG_L $2, PT_R2(sp) +#else +# define TRACE_IRQS_RELOAD_REGS \ + LONG_L $7, PT_R7(sp); \ + LONG_L $6, PT_R6(sp); \ + LONG_L $5, PT_R5(sp); \ + LONG_L $4, PT_R4(sp); \ + LONG_L $2, PT_R2(sp) +#endif # define TRACE_IRQS_ON \ + CLI; /* make sure trace_hardirqs_on() is called in kernel level */ \ jal trace_hardirqs_on +# define TRACE_IRQS_ON_RELOAD \ + TRACE_IRQS_ON; \ + TRACE_IRQS_RELOAD_REGS # define TRACE_IRQS_OFF \ jal trace_hardirqs_off #else # define TRACE_IRQS_ON +# define TRACE_IRQS_ON_RELOAD # define TRACE_IRQS_OFF #endif -- cgit v1.2.3 From 1df0f0ff7e56f6dcb1351b9490d55ebf91ff4bd8 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 26 Sep 2006 23:44:01 +0900 Subject: [MIPS] lockdep: Add STACKTRACE_SUPPORT and enable LOCKDEP_SUPPORT Implement stacktrace interface by using unwind_stack() and enable lockdep support in Kconfig. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 8 +++ arch/mips/kernel/Makefile | 1 + arch/mips/kernel/process.c | 1 + arch/mips/kernel/stacktrace.c | 111 ++++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/traps.c | 37 ++------------ include/asm-mips/stacktrace.h | 44 +++++++++++++++++ 6 files changed, 168 insertions(+), 34 deletions(-) create mode 100644 arch/mips/kernel/stacktrace.c create mode 100644 include/asm-mips/stacktrace.h (limited to 'include') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 30750c54bdf5..ba3a317ea42c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1841,6 +1841,14 @@ config RWSEM_GENERIC_SPINLOCK bool default y +config LOCKDEP_SUPPORT + bool + default y + +config STACKTRACE_SUPPORT + bool + default y + source "init/Kconfig" menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 881c467c6982..cd9cec9e39e9 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -11,6 +11,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o +obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o obj-$(CONFIG_APM) += apm.o diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 2613a0dd4b82..695538031c69 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef CONFIG_MIPS_MT_SMTC #include extern void smtc_idle_loop_hook(void); diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c new file mode 100644 index 000000000000..f851d0cc245f --- /dev/null +++ b/arch/mips/kernel/stacktrace.c @@ -0,0 +1,111 @@ +/* + * arch/mips/kernel/stacktrace.c + * + * Stack trace management functions + * + * Copyright (C) 2006 Atsushi Nemoto + */ +#include +#include +#include + +/* + * Save stack-backtrace addresses into a stack_trace buffer: + */ +static void save_raw_context_stack(struct stack_trace *trace, + unsigned int skip, unsigned long reg29) +{ + unsigned long *sp = (unsigned long *)reg29; + unsigned long addr; + + while (!kstack_end(sp)) { + addr = *sp++; + if (__kernel_text_address(addr)) { + if (!skip) + trace->entries[trace->nr_entries++] = addr; + else + skip--; + if (trace->nr_entries >= trace->max_entries) + break; + } + } +} + +static struct pt_regs * save_context_stack(struct stack_trace *trace, + unsigned int skip, struct task_struct *task, struct pt_regs *regs) +{ + unsigned long sp = regs->regs[29]; +#ifdef CONFIG_KALLSYMS + unsigned long ra = regs->regs[31]; + unsigned long pc = regs->cp0_epc; + extern void ret_from_irq(void); + + if (raw_show_trace || !__kernel_text_address(pc)) { + save_raw_context_stack(trace, skip, sp); + return NULL; + } + do { + if (!skip) + trace->entries[trace->nr_entries++] = pc; + else + skip--; + if (trace->nr_entries >= trace->max_entries) + break; + /* + * If we reached the bottom of interrupt context, + * return saved pt_regs. + */ + if (pc == (unsigned long)ret_from_irq) { + unsigned long stack_page = + (unsigned long)task_stack_page(task); + if (!stack_page || + sp < stack_page || + sp > stack_page + THREAD_SIZE - 32) + break; + return (struct pt_regs *)sp; + } + pc = unwind_stack(task, &sp, pc, ra); + ra = 0; + } while (pc); +#else + save_raw_context_stack(sp); +#endif + + return NULL; +} + +/* + * Save stack-backtrace addresses into a stack_trace buffer. + * If all_contexts is set, all contexts (hardirq, softirq and process) + * are saved. If not set then only the current context is saved. + */ +void save_stack_trace(struct stack_trace *trace, + struct task_struct *task, int all_contexts, + unsigned int skip) +{ + struct pt_regs dummyregs; + struct pt_regs *regs = &dummyregs; + + WARN_ON(trace->nr_entries || !trace->max_entries); + + if (task && task != current) { + regs->regs[29] = task->thread.reg29; + regs->regs[31] = 0; + regs->cp0_epc = task->thread.reg31; + } else { + if (!task) + task = current; + prepare_frametrace(regs); + } + + while (1) { + regs = save_context_stack(trace, skip, task, regs); + if (!all_contexts || !regs || + trace->nr_entries >= trace->max_entries) + break; + trace->entries[trace->nr_entries++] = ULONG_MAX; + if (trace->nr_entries >= trace->max_entries) + break; + skip = 0; + } +} diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e51d8fd9a152..440b8651fd8b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -41,6 +41,7 @@ #include #include #include +#include extern asmlinkage void handle_int(void); extern asmlinkage void handle_tlbm(void); @@ -92,16 +93,14 @@ static void show_raw_backtrace(unsigned long reg29) } #ifdef CONFIG_KALLSYMS -static int raw_show_trace; +int raw_show_trace; static int __init set_raw_show_trace(char *str) { raw_show_trace = 1; return 1; } __setup("raw_show_trace", set_raw_show_trace); - -extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, - unsigned long pc, unsigned long ra); +#endif static void show_backtrace(struct task_struct *task, struct pt_regs *regs) { @@ -121,9 +120,6 @@ static void show_backtrace(struct task_struct *task, struct pt_regs *regs) } while (pc); printk("\n"); } -#else -#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]); -#endif /* * This routine abuses get_user()/put_user() to reference pointers @@ -158,28 +154,6 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) show_backtrace(task, regs); } -static __always_inline void prepare_frametrace(struct pt_regs *regs) -{ - __asm__ __volatile__( - ".set push\n\t" - ".set noat\n\t" -#ifdef CONFIG_64BIT - "1: dla $1, 1b\n\t" - "sd $1, %0\n\t" - "sd $29, %1\n\t" - "sd $31, %2\n\t" -#else - "1: la $1, 1b\n\t" - "sw $1, %0\n\t" - "sw $29, %1\n\t" - "sw $31, %2\n\t" -#endif - ".set pop\n\t" - : "=m" (regs->cp0_epc), - "=m" (regs->regs[29]), "=m" (regs->regs[31]) - : : "memory"); -} - void show_stack(struct task_struct *task, unsigned long *sp) { struct pt_regs regs; @@ -206,11 +180,6 @@ void dump_stack(void) { struct pt_regs regs; - /* - * Remove any garbage that may be in regs (specially func - * addresses) to avoid show_raw_backtrace() to report them - */ - memset(®s, 0, sizeof(regs)); prepare_frametrace(®s); show_backtrace(current, ®s); } diff --git a/include/asm-mips/stacktrace.h b/include/asm-mips/stacktrace.h new file mode 100644 index 000000000000..231f6f897a61 --- /dev/null +++ b/include/asm-mips/stacktrace.h @@ -0,0 +1,44 @@ +#ifndef _ASM_STACKTRACE_H +#define _ASM_STACKTRACE_H + +#include + +#ifdef CONFIG_KALLSYMS +extern int raw_show_trace; +extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, + unsigned long pc, unsigned long ra); +#else +#define raw_show_trace 1 +#define unwind_stack(task, sp, pc, ra) 0 +#endif + +static __always_inline void prepare_frametrace(struct pt_regs *regs) +{ +#ifndef CONFIG_KALLSYMS + /* + * Remove any garbage that may be in regs (specially func + * addresses) to avoid show_raw_backtrace() to report them + */ + memset(regs, 0, sizeof(*regs)); +#endif + __asm__ __volatile__( + ".set push\n\t" + ".set noat\n\t" +#ifdef CONFIG_64BIT + "1: dla $1, 1b\n\t" + "sd $1, %0\n\t" + "sd $29, %1\n\t" + "sd $31, %2\n\t" +#else + "1: la $1, 1b\n\t" + "sw $1, %0\n\t" + "sw $29, %1\n\t" + "sw $31, %2\n\t" +#endif + ".set pop\n\t" + : "=m" (regs->cp0_epc), + "=m" (regs->regs[29]), "=m" (regs->regs[31]) + : : "memory"); +} + +#endif /* _ASM_STACKTRACE_H */ -- cgit v1.2.3 From c59a0f15be6e586aa0fe1fb5c7f740005c36ec56 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Sat, 2 Sep 2006 00:43:07 +0900 Subject: [MIPS] Remove __flush_icache_page __flash_icache_page is unused, so kill it. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/mm/c-r3k.c | 21 ------------ arch/mips/mm/c-r4k.c | 77 ------------------------------------------- arch/mips/mm/c-sb1.c | 61 ---------------------------------- arch/mips/mm/c-tx39.c | 29 ---------------- arch/mips/mm/cache.c | 1 - include/asm-mips/cacheflush.h | 2 -- 6 files changed, 191 deletions(-) (limited to 'include') diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index e1f35ef81145..d1af42c2a52e 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c @@ -268,26 +268,6 @@ static void r3k_flush_data_cache_page(unsigned long addr) { } -static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long physpage; - - if (cpu_context(smp_processor_id(), mm) == 0) - return; - - if (!(vma->vm_flags & VM_EXEC)) - return; - -#ifdef DEBUG_CACHE - printk("cpage[%d,%08lx]", cpu_context(smp_processor_id(), mm), page); -#endif - - physpage = (unsigned long) page_address(page); - if (physpage) - r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); -} - static void r3k_flush_cache_sigtramp(unsigned long addr) { unsigned long flags; @@ -335,7 +315,6 @@ void __init r3k_cache_init(void) flush_cache_mm = r3k_flush_cache_mm; flush_cache_range = r3k_flush_cache_range; flush_cache_page = r3k_flush_cache_page; - __flush_icache_page = r3k_flush_icache_page; flush_icache_range = r3k_flush_icache_range; flush_cache_sigtramp = r3k_flush_cache_sigtramp; diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 0b2da53750bd..cc895dad71d2 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -551,82 +551,6 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) instruction_hazard(); } -/* - * Ok, this seriously sucks. We use them to flush a user page but don't - * know the virtual address, so we have to blast away the whole icache - * which is significantly more expensive than the real thing. Otoh we at - * least know the kernel address of the page so we can flush it - * selectivly. - */ - -struct flush_icache_page_args { - struct vm_area_struct *vma; - struct page *page; -}; - -static inline void local_r4k_flush_icache_page(void *args) -{ - struct flush_icache_page_args *fip_args = args; - struct vm_area_struct *vma = fip_args->vma; - struct page *page = fip_args->page; - - /* - * Tricky ... Because we don't know the virtual address we've got the - * choice of either invalidating the entire primary and secondary - * caches or invalidating the secondary caches also. With the subset - * enforcment on R4000SC, R4400SC, R10000 and R12000 invalidating the - * secondary cache will result in any entries in the primary caches - * also getting invalidated which hopefully is a bit more economical. - */ - if (cpu_has_inclusive_pcaches) { - unsigned long addr = (unsigned long) page_address(page); - - r4k_blast_scache_page(addr); - ClearPageDcacheDirty(page); - - return; - } - - if (!cpu_has_ic_fills_f_dc) { - unsigned long addr = (unsigned long) page_address(page); - r4k_blast_dcache_page(addr); - if (!cpu_icache_snoops_remote_store) - r4k_blast_scache_page(addr); - ClearPageDcacheDirty(page); - } - - /* - * We're not sure of the virtual address(es) involved here, so - * we have to flush the entire I-cache. - */ - if (cpu_has_vtag_icache && vma->vm_mm == current->active_mm) { - int cpu = smp_processor_id(); - - if (cpu_context(cpu, vma->vm_mm) != 0) - drop_mmu_context(vma->vm_mm, cpu); - } else - r4k_blast_icache(); -} - -static void r4k_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - struct flush_icache_page_args args; - - /* - * If there's no context yet, or the page isn't executable, no I-cache - * flush is needed. - */ - if (!(vma->vm_flags & VM_EXEC)) - return; - - args.vma = vma; - args.page = page; - - r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1); -} - - #ifdef CONFIG_DMA_NONCOHERENT static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) @@ -1291,7 +1215,6 @@ void __init r4k_cache_init(void) __flush_cache_all = r4k___flush_cache_all; flush_cache_mm = r4k_flush_cache_mm; flush_cache_page = r4k_flush_cache_page; - __flush_icache_page = r4k_flush_icache_page; flush_cache_range = r4k_flush_cache_range; flush_cache_sigtramp = r4k_flush_cache_sigtramp; diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 16bad7c0a63f..5537558f19f7 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c @@ -306,66 +306,6 @@ void sb1_flush_icache_range(unsigned long start, unsigned long end) __attribute__((alias("local_sb1_flush_icache_range"))); #endif -/* - * Flush the icache for a given physical page. Need to writeback the - * dcache first, then invalidate the icache. If the page isn't - * executable, nothing is required. - */ -static void local_sb1_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - unsigned long start; - int cpu = smp_processor_id(); - -#ifndef CONFIG_SMP - if (!(vma->vm_flags & VM_EXEC)) - return; -#endif - - /* Need to writeback any dirty data for that page, we have the PA */ - start = (unsigned long)(page-mem_map) << PAGE_SHIFT; - __sb1_writeback_inv_dcache_phys_range(start, start + PAGE_SIZE); - /* - * If there's a context, bump the ASID (cheaper than a flush, - * since we don't know VAs!) - */ - if (vma->vm_mm == current->active_mm) { - if (cpu_context(cpu, vma->vm_mm) != 0) - drop_mmu_context(vma->vm_mm, cpu); - } else - __sb1_flush_icache_range(start, start + PAGE_SIZE); - -} - -#ifdef CONFIG_SMP -struct flush_icache_page_args { - struct vm_area_struct *vma; - struct page *page; -}; - -static void sb1_flush_icache_page_ipi(void *info) -{ - struct flush_icache_page_args *args = info; - local_sb1_flush_icache_page(args->vma, args->page); -} - -/* Dirty dcache could be on another CPU, so do the IPIs */ -static void sb1_flush_icache_page(struct vm_area_struct *vma, - struct page *page) -{ - struct flush_icache_page_args args; - - if (!(vma->vm_flags & VM_EXEC)) - return; - args.vma = vma; - args.page = page; - on_each_cpu(sb1_flush_icache_page_ipi, (void *) &args, 1, 1); -} -#else -void sb1_flush_icache_page(struct vm_area_struct *vma, struct page *page) - __attribute__((alias("local_sb1_flush_icache_page"))); -#endif - /* * A signal trampoline must fit into a single cacheline. */ @@ -526,7 +466,6 @@ void sb1_cache_init(void) /* These routines are for Icache coherence with the Dcache */ flush_icache_range = sb1_flush_icache_range; - __flush_icache_page = sb1_flush_icache_page; flush_icache_all = __sb1_flush_icache_all; /* local only */ /* This implies an Icache flush too, so can't be nop'ed */ diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 932a09d7ef84..f32ebde30ccf 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c @@ -248,33 +248,6 @@ static void tx39_flush_icache_range(unsigned long start, unsigned long end) } } -/* - * Ok, this seriously sucks. We use them to flush a user page but don't - * know the virtual address, so we have to blast away the whole icache - * which is significantly more expensive than the real thing. Otoh we at - * least know the kernel address of the page so we can flush it - * selectivly. - */ -static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page) -{ - unsigned long addr; - /* - * If there's no context yet, or the page isn't executable, no icache - * flush is needed. - */ - if (!(vma->vm_flags & VM_EXEC)) - return; - - addr = (unsigned long) page_address(page); - tx39_blast_dcache_page(addr); - - /* - * We're not sure of the virtual address(es) involved here, so - * we have to flush the entire I-cache. - */ - tx39_blast_icache(); -} - static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) { unsigned long end; @@ -382,7 +355,6 @@ void __init tx39_cache_init(void) flush_cache_mm = (void *) tx39h_flush_icache_all; flush_cache_range = (void *) tx39h_flush_icache_all; flush_cache_page = (void *) tx39h_flush_icache_all; - __flush_icache_page = (void *) tx39h_flush_icache_all; flush_icache_range = (void *) tx39h_flush_icache_all; flush_cache_sigtramp = (void *) tx39h_flush_icache_all; @@ -408,7 +380,6 @@ void __init tx39_cache_init(void) flush_cache_mm = tx39_flush_cache_mm; flush_cache_range = tx39_flush_cache_range; flush_cache_page = tx39_flush_cache_page; - __flush_icache_page = tx39_flush_icache_page; flush_icache_range = tx39_flush_icache_range; flush_cache_sigtramp = tx39_flush_cache_sigtramp; diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 40c8b0235183..caf807ded514 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -25,7 +25,6 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); void (*flush_icache_range)(unsigned long start, unsigned long end); -void (*__flush_icache_page)(struct vm_area_struct *vma, struct page *page); /* MIPS specific cache operations */ void (*flush_cache_sigtramp)(unsigned long addr); diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h index 36416fdfcf68..9ab59e2bb233 100644 --- a/include/asm-mips/cacheflush.h +++ b/include/asm-mips/cacheflush.h @@ -46,8 +46,6 @@ static inline void flush_dcache_page(struct page *page) #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -extern void (*__flush_icache_page)(struct vm_area_struct *vma, - struct page *page); static inline void flush_icache_page(struct vm_area_struct *vma, struct page *page) { -- cgit v1.2.3 From 1924600cdb3143cdcc32b6fa43325739503659b9 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Fri, 29 Sep 2006 18:02:51 +0900 Subject: [MIPS] Make unwind_stack() can dig into interrupted context If the PC was ret_from_irq or ret_from_exception, there will be no more normal stackframe. Instead of stopping the unwinding, use PC and RA saved by an exception handler to continue unwinding into the interrupted context. This also simplifies the CONFIG_STACKTRACE code. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 36 +++++++++++++++++++++++++++++++----- arch/mips/kernel/stacktrace.c | 32 ++++++-------------------------- arch/mips/kernel/traps.c | 3 +-- include/asm-mips/stacktrace.h | 2 +- 4 files changed, 39 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 695538031c69..045d987bc683 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -399,7 +399,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) #ifdef CONFIG_KALLSYMS /* used by show_backtrace() */ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, - unsigned long pc, unsigned long ra) + unsigned long pc, unsigned long *ra) { unsigned long stack_page; struct mips_frame_info info; @@ -407,18 +407,42 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, char namebuf[KSYM_NAME_LEN + 1]; unsigned long size, ofs; int leaf; + extern void ret_from_irq(void); + extern void ret_from_exception(void); stack_page = (unsigned long)task_stack_page(task); if (!stack_page) return 0; + /* + * If we reached the bottom of interrupt context, + * return saved pc in pt_regs. + */ + if (pc == (unsigned long)ret_from_irq || + pc == (unsigned long)ret_from_exception) { + struct pt_regs *regs; + if (*sp >= stack_page && + *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) { + regs = (struct pt_regs *)*sp; + pc = regs->cp0_epc; + if (__kernel_text_address(pc)) { + *sp = regs->regs[29]; + *ra = regs->regs[31]; + return pc; + } + } + return 0; + } if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) return 0; /* * Return ra if an exception occured at the first instruction */ - if (unlikely(ofs == 0)) - return ra; + if (unlikely(ofs == 0)) { + pc = *ra; + *ra = 0; + return pc; + } info.func = (void *)(pc - ofs); info.func_size = ofs; /* analyze from start to ofs */ @@ -437,11 +461,12 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, * one. In that cases avoid to return always the * same value. */ - pc = pc != ra ? ra : 0; + pc = pc != *ra ? *ra : 0; else pc = ((unsigned long *)(*sp))[info.pc_offset]; *sp += info.frame_size; + *ra = 0; return __kernel_text_address(pc) ? pc : 0; } #endif @@ -454,6 +479,7 @@ unsigned long get_wchan(struct task_struct *task) unsigned long pc = 0; #ifdef CONFIG_KALLSYMS unsigned long sp; + unsigned long ra = 0; #endif if (!task || task == current || task->state == TASK_RUNNING) @@ -467,7 +493,7 @@ unsigned long get_wchan(struct task_struct *task) sp = task->thread.reg29 + schedule_mfi.frame_size; while (in_sched_functions(pc)) - pc = unwind_stack(task, &sp, pc, 0); + pc = unwind_stack(task, &sp, pc, &ra); #endif out: diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 676e6f69d24b..4aabe526a68e 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -31,23 +31,21 @@ static void save_raw_context_stack(struct stack_trace *trace, } } -static struct pt_regs * save_context_stack(struct stack_trace *trace, +static void save_context_stack(struct stack_trace *trace, struct task_struct *task, struct pt_regs *regs) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS unsigned long ra = regs->regs[31]; unsigned long pc = regs->cp0_epc; - unsigned long stack_page = - (unsigned long)task_stack_page(task); - extern void ret_from_irq(void); - extern void ret_from_exception(void); if (raw_show_trace || !__kernel_text_address(pc)) { + unsigned long stack_page = + (unsigned long)task_stack_page(task); if (stack_page && sp >= stack_page && sp <= stack_page + THREAD_SIZE - 32) save_raw_context_stack(trace, sp); - return NULL; + return; } do { if (trace->skip > 0) @@ -56,25 +54,11 @@ static struct pt_regs * save_context_stack(struct stack_trace *trace, trace->entries[trace->nr_entries++] = pc; if (trace->nr_entries >= trace->max_entries) break; - /* - * If we reached the bottom of interrupt context, - * return saved pt_regs. - */ - if (pc == (unsigned long)ret_from_irq || - pc == (unsigned long)ret_from_exception) { - if (stack_page && sp >= stack_page && - sp <= stack_page + THREAD_SIZE - 32) - return (struct pt_regs *)sp; - break; - } - pc = unwind_stack(task, &sp, pc, ra); - ra = 0; + pc = unwind_stack(task, &sp, pc, &ra); } while (pc); #else save_raw_context_stack(sp); #endif - - return NULL; } /* @@ -97,9 +81,5 @@ void save_stack_trace(struct stack_trace *trace, struct task_struct *task) prepare_frametrace(regs); } - while (1) { - regs = save_context_stack(trace, task, regs); - if (!regs || trace->nr_entries >= trace->max_entries) - break; - } + save_context_stack(trace, task, regs); } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 440b8651fd8b..b7292a56d4cd 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -115,8 +115,7 @@ static void show_backtrace(struct task_struct *task, struct pt_regs *regs) printk("Call Trace:\n"); do { print_ip_sym(pc); - pc = unwind_stack(task, &sp, pc, ra); - ra = 0; + pc = unwind_stack(task, &sp, pc, &ra); } while (pc); printk("\n"); } diff --git a/include/asm-mips/stacktrace.h b/include/asm-mips/stacktrace.h index 231f6f897a61..07f873351a86 100644 --- a/include/asm-mips/stacktrace.h +++ b/include/asm-mips/stacktrace.h @@ -6,7 +6,7 @@ #ifdef CONFIG_KALLSYMS extern int raw_show_trace; extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, - unsigned long pc, unsigned long ra); + unsigned long pc, unsigned long *ra); #else #define raw_show_trace 1 #define unwind_stack(task, sp, pc, ra) 0 -- cgit v1.2.3 From 998ec2901aea9f412d2dc3e29a3c20f377793916 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sun, 1 Oct 2006 19:35:28 +0900 Subject: [MIPS] Add UART IRQ number for EV64120 Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/mach-ev64120/mach-gt64120.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/asm-mips/mach-ev64120/mach-gt64120.h b/include/asm-mips/mach-ev64120/mach-gt64120.h index 13b1443a7a65..7e272ce57ea3 100644 --- a/include/asm-mips/mach-ev64120/mach-gt64120.h +++ b/include/asm-mips/mach-ev64120/mach-gt64120.h @@ -42,6 +42,7 @@ extern unsigned long gt64120_base; #define EV64120_UART0_REGS_BASE (KSEG1ADDR(EV64120_COM1_BASE_ADDR)) #define EV64120_UART1_REGS_BASE (KSEG1ADDR(EV64120_COM2_BASE_ADDR)) #define EV64120_BASE_BAUD ( 3686400 / 16 ) +#define EV64120_UART_IRQ 6 /* * PCI interrupts will come in on either the INTA or INTD interrups lines, -- cgit v1.2.3 From b772da30b4b22230c214f37429edcd7ddbf641e1 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sun, 1 Oct 2006 19:43:27 +0900 Subject: [MIPS] Rename SERIAL_PORT_DEFNS for EV64120 Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/serial.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h index 035637c67e7c..c882e04e1497 100644 --- a/include/asm-mips/serial.h +++ b/include/asm-mips/serial.h @@ -55,19 +55,18 @@ * Galileo EV64120 evaluation board */ #ifdef CONFIG_MIPS_EV64120 -#include -#include -#define EV96100_SERIAL_PORT_DEFNS \ - { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \ +#include +#define EV64120_SERIAL_PORT_DEFNS \ + { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \ .flags = STD_COM_FLAGS, \ - .iomem_base = EV96100_UART0_REGS_BASE, .iomem_reg_shift = 2, \ + .iomem_base = EV64120_UART0_REGS_BASE, .iomem_reg_shift = 2, \ .io_type = SERIAL_IO_MEM }, \ - { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \ + { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \ .flags = STD_COM_FLAGS, \ - .iomem_base = EV96100_UART1_REGS_BASE, .iomem_reg_shift = 2, \ + .iomem_base = EV64120_UART1_REGS_BASE, .iomem_reg_shift = 2, \ .io_type = SERIAL_IO_MEM }, #else -#define EV96100_SERIAL_PORT_DEFNS +#define EV64120_SERIAL_PORT_DEFNS #endif #ifdef CONFIG_MIPS_ITE8172 @@ -239,7 +238,7 @@ #define SERIAL_PORT_DFNS \ DDB5477_SERIAL_PORT_DEFNS \ - EV96100_SERIAL_PORT_DEFNS \ + EV64120_SERIAL_PORT_DEFNS \ IP32_SERIAL_PORT_DEFNS \ ITE_SERIAL_PORT_DEFNS \ IVR_SERIAL_PORT_DEFNS \ -- cgit v1.2.3 From 04b314b2c3732bb5aa752fdbb3076de16decdab6 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sun, 1 Oct 2006 19:47:08 +0900 Subject: [MIPS] Remove unused galileo-boars header files Signed-off-by: Yoichi Yuasa Signed-off-by: Ralf Baechle --- include/asm-mips/galileo-boards/ev96100.h | 55 ---------------------------- include/asm-mips/galileo-boards/ev96100int.h | 12 ------ 2 files changed, 67 deletions(-) delete mode 100644 include/asm-mips/galileo-boards/ev96100.h delete mode 100644 include/asm-mips/galileo-boards/ev96100int.h (limited to 'include') diff --git a/include/asm-mips/galileo-boards/ev96100.h b/include/asm-mips/galileo-boards/ev96100.h deleted file mode 100644 index 070dfd84a8e8..000000000000 --- a/include/asm-mips/galileo-boards/ev96100.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * - */ -#ifndef _MIPS_EV96100_H -#define _MIPS_EV96100_H - -#include - -/* - * GT64120 config space base address - */ -#define GT64120_BASE (KSEG1ADDR(0x14000000)) -#define MIPS_GT_BASE GT64120_BASE - -/* - * PCI Bus allocation - */ -#define GT_PCI_MEM_BASE 0x12000000UL -#define GT_PCI_MEM_SIZE 0x02000000UL -#define GT_PCI_IO_BASE 0x10000000UL -#define GT_PCI_IO_SIZE 0x02000000UL -#define GT_ISA_IO_BASE PCI_IO_BASE - -/* - * Duart I/O ports. - */ -#define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20) -#define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00) - - -/* - * EV96100 interrupt controller register base. - */ -#define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000)) - -/* - * EV96100 UART register base. - */ -#define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR -#define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR -#define EV96100_BASE_BAUD ( 3686400 / 16 ) - - -/* - * Because of an error/peculiarity in the Galileo chip, we need to swap the - * bytes when running bigendian. - */ -#define __GT_READ(ofs) \ - (*(volatile u32 *)(GT64120_BASE+(ofs))) -#define __GT_WRITE(ofs, data) \ - do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) -#define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs)) -#define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data)) - -#endif /* !(_MIPS_EV96100_H) */ diff --git a/include/asm-mips/galileo-boards/ev96100int.h b/include/asm-mips/galileo-boards/ev96100int.h deleted file mode 100644 index c58b16d06d6e..000000000000 --- a/include/asm-mips/galileo-boards/ev96100int.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * - */ -#ifndef _MIPS_EV96100INT_H -#define _MIPS_EV96100INT_H - -#define EV96100INT_UART_0 6 /* IP 6 */ -#define EV96100INT_TIMER 7 /* IP 7 */ - -extern void ev96100int_init(void); - -#endif /* !(_MIPS_EV96100_H) */ -- cgit v1.2.3