From 10e267234cc0133bc9ed26bc34eb09de90c248c0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 16 Nov 2006 13:38:57 -0800 Subject: [SPARC64]: Add irqtrace/stacktrace/lockdep support. Signed-off-by: David S. Miller --- include/asm-sparc64/irqflags.h | 89 ++++++++++++++++++++++++++++++++++++++++++ include/asm-sparc64/rwsem.h | 32 +++++++++++---- include/asm-sparc64/system.h | 49 ++--------------------- include/asm-sparc64/ttable.h | 45 ++++++++++++++++++++- 4 files changed, 160 insertions(+), 55 deletions(-) create mode 100644 include/asm-sparc64/irqflags.h (limited to 'include') diff --git a/include/asm-sparc64/irqflags.h b/include/asm-sparc64/irqflags.h new file mode 100644 index 000000000000..024fc54d0682 --- /dev/null +++ b/include/asm-sparc64/irqflags.h @@ -0,0 +1,89 @@ +/* + * include/asm-sparc64/irqflags.h + * + * IRQ flags handling + * + * This file gets included from lowlevel asm headers too, to provide + * wrapped versions of the local_irq_*() APIs, based on the + * raw_local_irq_*() functions from the lowlevel headers. + */ +#ifndef _ASM_IRQFLAGS_H +#define _ASM_IRQFLAGS_H + +#ifndef __ASSEMBLY__ + +static inline unsigned long __raw_local_save_flags(void) +{ + unsigned long flags; + + __asm__ __volatile__( + "rdpr %%pil, %0" + : "=r" (flags) + ); + + return flags; +} + +#define raw_local_save_flags(flags) \ + do { (flags) = __raw_local_save_flags(); } while (0) + +static inline void raw_local_irq_restore(unsigned long flags) +{ + __asm__ __volatile__( + "wrpr %0, %%pil" + : /* no output */ + : "r" (flags) + : "memory" + ); +} + +static inline void raw_local_irq_disable(void) +{ + __asm__ __volatile__( + "wrpr 15, %%pil" + : /* no outputs */ + : /* no inputs */ + : "memory" + ); +} + +static inline void raw_local_irq_enable(void) +{ + __asm__ __volatile__( + "wrpr 0, %%pil" + : /* no outputs */ + : /* no inputs */ + : "memory" + ); +} + +static inline int raw_irqs_disabled_flags(unsigned long flags) +{ + return (flags > 0); +} + +static inline int raw_irqs_disabled(void) +{ + unsigned long flags = __raw_local_save_flags(); + + return raw_irqs_disabled_flags(flags); +} + +/* + * For spinlocks, etc: + */ +static inline unsigned long __raw_local_irq_save(void) +{ + unsigned long flags = __raw_local_save_flags(); + + raw_local_irq_disable(); + + return flags; +} + +#define raw_local_irq_save(flags) \ + do { (flags) = __raw_local_irq_save(); } while (0) + +#endif /* (__ASSEMBLY__) */ + +#endif /* !(_ASM_IRQFLAGS_H) */ diff --git a/include/asm-sparc64/rwsem.h b/include/asm-sparc64/rwsem.h index cef5e8270421..1294b7ce5d06 100644 --- a/include/asm-sparc64/rwsem.h +++ b/include/asm-sparc64/rwsem.h @@ -23,20 +23,33 @@ struct rw_semaphore { signed int count; spinlock_t wait_lock; struct list_head wait_list; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif }; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } +#else +# define __RWSEM_DEP_MAP_INIT(lockname) +#endif + #define __RWSEM_INITIALIZER(name) \ -{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) } +{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \ + __RWSEM_DEP_MAP_INIT(name) } #define DECLARE_RWSEM(name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name) -static __inline__ void init_rwsem(struct rw_semaphore *sem) -{ - sem->count = RWSEM_UNLOCKED_VALUE; - spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} +extern void __init_rwsem(struct rw_semaphore *sem, const char *name, + struct lock_class_key *key); + +#define init_rwsem(sem) \ +do { \ + static struct lock_class_key __key; \ + \ + __init_rwsem((sem), #sem, &__key); \ +} while (0) extern void __down_read(struct rw_semaphore *sem); extern int __down_read_trylock(struct rw_semaphore *sem); @@ -46,6 +59,11 @@ extern void __up_read(struct rw_semaphore *sem); extern void __up_write(struct rw_semaphore *sem); extern void __downgrade_write(struct rw_semaphore *sem); +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) +{ + __down_write(sem); +} + static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) { return atomic_add_return(delta, (atomic_t *)(&sem->count)); diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index a8b7432c9a70..32281acb878b 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -7,6 +7,9 @@ #include #ifndef __ASSEMBLY__ + +#include + /* * Sparc (general) CPU types */ @@ -72,52 +75,6 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ #endif -#define setipl(__new_ipl) \ - __asm__ __volatile__("wrpr %0, %%pil" : : "r" (__new_ipl) : "memory") - -#define local_irq_disable() \ - __asm__ __volatile__("wrpr 15, %%pil" : : : "memory") - -#define local_irq_enable() \ - __asm__ __volatile__("wrpr 0, %%pil" : : : "memory") - -#define getipl() \ -({ unsigned long retval; __asm__ __volatile__("rdpr %%pil, %0" : "=r" (retval)); retval; }) - -#define swap_pil(__new_pil) \ -({ unsigned long retval; \ - __asm__ __volatile__("rdpr %%pil, %0\n\t" \ - "wrpr %1, %%pil" \ - : "=&r" (retval) \ - : "r" (__new_pil) \ - : "memory"); \ - retval; \ -}) - -#define read_pil_and_cli() \ -({ unsigned long retval; \ - __asm__ __volatile__("rdpr %%pil, %0\n\t" \ - "wrpr 15, %%pil" \ - : "=r" (retval) \ - : : "memory"); \ - retval; \ -}) - -#define local_save_flags(flags) ((flags) = getipl()) -#define local_irq_save(flags) ((flags) = read_pil_and_cli()) -#define local_irq_restore(flags) setipl((flags)) - -/* On sparc64 IRQ flags are the PIL register. A value of zero - * means all interrupt levels are enabled, any other value means - * only IRQ levels greater than that value will be received. - * Consequently this means that the lowest IRQ level is one. - */ -#define irqs_disabled() \ -({ unsigned long flags; \ - local_save_flags(flags);\ - (flags > 0); \ -}) - #define nop() __asm__ __volatile__ ("nop") #define read_barrier_depends() do { } while(0) diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h index f2352606a79f..c2a16e188499 100644 --- a/include/asm-sparc64/ttable.h +++ b/include/asm-sparc64/ttable.h @@ -137,10 +137,49 @@ #endif #define BREAKPOINT_TRAP TRAP(breakpoint_trap) +#ifdef CONFIG_TRACE_IRQFLAGS + +#define TRAP_IRQ(routine, level) \ + rdpr %pil, %g2; \ + wrpr %g0, 15, %pil; \ + sethi %hi(1f-4), %g7; \ + ba,pt %xcc, etrap_irq; \ + or %g7, %lo(1f-4), %g7; \ + nop; \ + nop; \ + nop; \ + .subsection 2; \ +1: call trace_hardirqs_off; \ + nop; \ + mov level, %o0; \ + call routine; \ + add %sp, PTREGS_OFF, %o1; \ + ba,a,pt %xcc, rtrap_irq; \ + .previous; + +#define TICK_SMP_IRQ \ + rdpr %pil, %g2; \ + wrpr %g0, 15, %pil; \ + sethi %hi(1f-4), %g7; \ + ba,pt %xcc, etrap_irq; \ + or %g7, %lo(1f-4), %g7; \ + nop; \ + nop; \ + nop; \ + .subsection 2; \ +1: call trace_hardirqs_off; \ + nop; \ + call smp_percpu_timer_interrupt; \ + add %sp, PTREGS_OFF, %o0; \ + ba,a,pt %xcc, rtrap_irq; \ + .previous; + +#else + #define TRAP_IRQ(routine, level) \ rdpr %pil, %g2; \ wrpr %g0, 15, %pil; \ - b,pt %xcc, etrap_irq; \ + ba,pt %xcc, etrap_irq; \ rd %pc, %g7; \ mov level, %o0; \ call routine; \ @@ -151,12 +190,14 @@ rdpr %pil, %g2; \ wrpr %g0, 15, %pil; \ sethi %hi(109f), %g7; \ - b,pt %xcc, etrap_irq; \ + ba,pt %xcc, etrap_irq; \ 109: or %g7, %lo(109b), %g7; \ call smp_percpu_timer_interrupt; \ add %sp, PTREGS_OFF, %o0; \ ba,a,pt %xcc, rtrap_irq; +#endif + #define TRAP_IVEC TRAP_NOSAVE(do_ivec) #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl) -- cgit v1.2.1 From 5ff42459af99427a393e3b576a77a900d43e730a Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Fri, 1 Dec 2006 20:19:59 -0800 Subject: [SPARC64]: dma remove extra brackets Signed-off-by: Mariusz Kozlowski Signed-off-by: David S. Miller --- include/asm-sparc64/dma.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/asm-sparc64/dma.h b/include/asm-sparc64/dma.h index 27f65972b3bb..93e5a062df88 100644 --- a/include/asm-sparc64/dma.h +++ b/include/asm-sparc64/dma.h @@ -152,9 +152,9 @@ extern void dvma_init(struct sbus_bus *); #define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL)) /* Yes, I hack a lot of elisp in my spare time... */ -#define DMA_ERROR_P(regs) (((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR)) -#define DMA_IRQ_P(regs) (((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))) -#define DMA_WRITE_P(regs) (((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE)) +#define DMA_ERROR_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR)) +#define DMA_IRQ_P(regs) ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) +#define DMA_WRITE_P(regs) ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE)) #define DMA_OFF(__regs) \ do { u32 tmp = sbus_readl((__regs) + DMA_CSR); \ tmp &= ~DMA_ENABLE; \ -- cgit v1.2.1 From f0882589666440d573f657cb3a1d5f66f3caa157 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 10 Dec 2006 02:42:03 -0800 Subject: [SPARC64]: Fix several kprobes bugs. - relbranch_fixup(), for non-branches, would end up setting regs->tnpc incorrectly, in fact it would set it equal to regs->tpc which would cause that instruction to execute twice Also, if this is not a PC-relative branch, we should just leave regs->tnpc as-is. This covers cases like 'jmpl' which branch to absolute values. - To be absolutely %100 safe, we need to flush the instruction cache for all assignments to kprobe->ainsn.insn[], including cases like add_aggr_kprobe() - prev_kprobe's status field needs to be 'unsigned long' to match the type of the value it is saving - jprobes were totally broken: = jprobe_return() can run in the stack frame of the jprobe handler, or in an even deeper stack frame, thus we'll be in the wrong register window than the one from the original probe state. So unwind using 'restore' instructions, if necessary, right before we do the jprobe_return() breakpoint trap. = There is no reason to save/restore the register window saved at %sp at jprobe trigger time. Those registers cannot be modified by the jprobe handler. Also, this code was saving and restoring "sizeof (struct sparc_stackf)" bytes. Depending upon the caller, this could clobber unrelated stack frame pieces if there is only a basic 128-byte register window stored on the stack, without the argument save area. So just saving and restoring struct pt_regs is sufficient. = Kill the "jprobe_saved_esp", totally unused. Also, delete "jprobe_saved_regs_location", with the stack frame unwind now done explicitly by jprobe_return(), this check is superfluous. Signed-off-by: David S. Miller --- include/asm-sparc64/kprobes.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index c9f5c34d318c..becc38fa06c5 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h @@ -13,7 +13,11 @@ typedef u32 kprobe_opcode_t; #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define arch_remove_kprobe(p) do {} while (0) #define ARCH_INACTIVE_KPROBE_COUNT 0 -#define flush_insn_slot(p) do { } while (0) + +#define flush_insn_slot(p) \ +do { flushi(&(p)->ainsn.insn[0]); \ + flushi(&(p)->ainsn.insn[1]); \ +} while (0) /* Architecture specific copy of original instruction*/ struct arch_specific_insn { @@ -23,7 +27,7 @@ struct arch_specific_insn { struct prev_kprobe { struct kprobe *kp; - unsigned int status; + unsigned long status; unsigned long orig_tnpc; unsigned long orig_tstate_pil; }; @@ -33,10 +37,7 @@ struct kprobe_ctlblk { unsigned long kprobe_status; unsigned long kprobe_orig_tnpc; unsigned long kprobe_orig_tstate_pil; - long *jprobe_saved_esp; struct pt_regs jprobe_saved_regs; - struct pt_regs *jprobe_saved_regs_location; - struct sparc_stackf jprobe_saved_stack; struct prev_kprobe prev_kprobe; }; -- cgit v1.2.1