Commit 44d2d371 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  sparc64: Add some more commentary to __raw_local_irq_save()
  sparc64: Fix memory leak in pci_register_iommu_region().
  sparc64: Add kmemleak annotation to sun4v_build_virq()
  sparc64: Support kmemleak.
  sparc64: Add function graph tracer support.
  sparc64: Give a stack frame to the ftrace call sites.
  sparc64: Use a seperate counter for timer interrupts and NMI checks, like x86.
  sparc64: Remove profiling from some low-level bits.
  sparc64: Kill unnecessary static on local var in ftrace_call_replace().
  sparc64: Kill CONFIG_STACK_DEBUG code.
  sparc64: Add HAVE_FUNCTION_TRACE_MCOUNT_TEST and tidy up.
  sparc64: Adjust __raw_local_irq_save() to cooperate in NMIs.
  sparc64: Use kstack_valid() in die_if_kernel().
parents 465de2ba c011f80b
......@@ -37,6 +37,9 @@ config SPARC64
def_bool 64BIT
select ARCH_SUPPORTS_MSI
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_GRAPH_FP_TEST
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_KRETPROBES
select HAVE_KPROBES
select HAVE_LMB
......
......@@ -19,13 +19,10 @@ config DEBUG_DCFLUSH
bool "D-cache flush debugging"
depends on SPARC64 && DEBUG_KERNEL
config STACK_DEBUG
bool "Stack Overflow Detection Support"
config MCOUNT
bool
depends on SPARC64
depends on STACK_DEBUG || FUNCTION_TRACER
depends on FUNCTION_TRACER
default y
config FRAME_POINTER
......
......@@ -17,7 +17,7 @@ typedef struct {
unsigned int __nmi_count;
unsigned long clock_tick; /* %tick's per second */
unsigned long __pad;
unsigned int __pad1;
unsigned int irq0_irqs;
unsigned int __pad2;
/* Dcache line 2, rarely used */
......
......@@ -76,9 +76,26 @@ static inline int raw_irqs_disabled(void)
*/
static inline unsigned long __raw_local_irq_save(void)
{
unsigned long flags = __raw_local_save_flags();
raw_local_irq_disable();
unsigned long flags, tmp;
/* Disable interrupts to PIL_NORMAL_MAX unless we already
* are using PIL_NMI, in which case PIL_NMI is retained.
*
* The only values we ever program into the %pil are 0,
* PIL_NORMAL_MAX and PIL_NMI.
*
* Since PIL_NMI is the largest %pil value and all bits are
* set in it (0xf), it doesn't matter what PIL_NORMAL_MAX
* actually is.
*/
__asm__ __volatile__(
"rdpr %%pil, %0\n\t"
"or %0, %2, %1\n\t"
"wrpr %1, 0x0, %%pil"
: "=r" (flags), "=r" (tmp)
: "i" (PIL_NORMAL_MAX)
: "memory"
);
return flags;
}
......
......@@ -13,6 +13,14 @@ extra-y += init_task.o
CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS)
extra-y += vmlinux.lds
ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
CFLAGS_REMOVE_ftrace.o := -pg
CFLAGS_REMOVE_time_$(BITS).o := -pg
CFLAGS_REMOVE_perf_event.o := -pg
CFLAGS_REMOVE_pcr.o := -pg
endif
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
obj-$(CONFIG_SPARC32) += etrap_32.o
obj-$(CONFIG_SPARC32) += rtrap_32.o
......@@ -85,7 +93,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
CFLAGS_REMOVE_ftrace.o := -pg
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_EARLYFB) += btext.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
......
......@@ -13,7 +13,7 @@ static const u32 ftrace_nop = 0x01000000;
static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
{
static u32 call;
u32 call;
s32 off;
off = ((s32)addr - (s32)ip);
......@@ -91,3 +91,61 @@ int __init ftrace_dyn_arch_init(void *data)
return 0;
}
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
extern void ftrace_graph_call(void);
int ftrace_enable_ftrace_graph_caller(void)
{
unsigned long ip = (unsigned long)(&ftrace_graph_call);
u32 old, new;
old = *(u32 *) &ftrace_graph_call;
new = ftrace_call_replace(ip, (unsigned long) &ftrace_graph_caller);
return ftrace_modify_code(ip, old, new);
}
int ftrace_disable_ftrace_graph_caller(void)
{
unsigned long ip = (unsigned long)(&ftrace_graph_call);
u32 old, new;
old = *(u32 *) &ftrace_graph_call;
new = ftrace_call_replace(ip, (unsigned long) &ftrace_stub);
return ftrace_modify_code(ip, old, new);
}
#endif /* !CONFIG_DYNAMIC_FTRACE */
/*
* Hook the return address and push it in the stack of return addrs
* in current thread info.
*/
unsigned long prepare_ftrace_return(unsigned long parent,
unsigned long self_addr,
unsigned long frame_pointer)
{
unsigned long return_hooker = (unsigned long) &return_to_handler;
struct ftrace_graph_ent trace;
if (unlikely(atomic_read(&current->tracing_graph_pause)))
return parent + 8UL;
if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
frame_pointer) == -EBUSY)
return parent + 8UL;
trace.func = self_addr;
/* Only trace if the calling function expects to */
if (!ftrace_graph_entry(&trace)) {
current->curr_ret_stack--;
return parent + 8UL;
}
return return_hooker;
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
......@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/ftrace.h>
#include <linux/irq.h>
#include <asm/ptrace.h>
......@@ -647,6 +648,14 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
if (unlikely(!bucket))
return 0;
/* The only reference we store to the IRQ bucket is
* by physical address which kmemleak can't see, tell
* it that this object explicitly is not a leak and
* should be scanned.
*/
kmemleak_not_leak(bucket);
__flush_dcache_range((unsigned long) bucket,
((unsigned long) bucket +
sizeof(struct ino_bucket)));
......@@ -721,7 +730,7 @@ static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
__asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
}
void handler_irq(int irq, struct pt_regs *regs)
void __irq_entry handler_irq(int irq, struct pt_regs *regs)
{
unsigned long pstate, bucket_pa;
struct pt_regs *old_regs;
......
......@@ -5,6 +5,7 @@
#include <linux/kgdb.h>
#include <linux/kdebug.h>
#include <linux/ftrace.h>
#include <asm/kdebug.h>
#include <asm/ptrace.h>
......@@ -108,7 +109,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
}
#ifdef CONFIG_SMP
void smp_kgdb_capture_client(int irq, struct pt_regs *regs)
void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs)
{
unsigned long flags;
......
......@@ -92,7 +92,6 @@ static void die_nmi(const char *str, struct pt_regs *regs, int do_panic)
notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
{
unsigned int sum, touched = 0;
int cpu = smp_processor_id();
clear_softint(1 << irq);
......@@ -106,7 +105,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
else
pcr_ops->write(PCR_PIC_PRIV);
sum = kstat_irqs_cpu(0, cpu);
sum = local_cpu_data().irq0_irqs;
if (__get_cpu_var(nmi_touch)) {
__get_cpu_var(nmi_touch) = 0;
touched = 1;
......
......@@ -371,14 +371,19 @@ static void pci_register_iommu_region(struct pci_pbm_info *pbm)
struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL);
if (!rp) {
prom_printf("Cannot allocate IOMMU resource.\n");
prom_halt();
pr_info("%s: Cannot allocate IOMMU resource.\n",
pbm->name);
return;
}
rp->name = "IOMMU";
rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
rp->flags = IORESOURCE_BUSY;
request_resource(&pbm->mem_space, rp);
if (request_resource(&pbm->mem_space, rp)) {
pr_info("%s: Unable to request IOMMU resource.\n",
pbm->name);
kfree(rp);
}
}
}
......
......@@ -8,6 +8,7 @@
#include <linux/irq.h>
#include <linux/perf_event.h>
#include <linux/ftrace.h>
#include <asm/pil.h>
#include <asm/pcr.h>
......@@ -34,7 +35,7 @@ unsigned int picl_shift;
* Therefore in such situations we defer the work by signalling
* a lower level cpu IRQ.
*/
void deferred_pcr_work_irq(int irq, struct pt_regs *regs)
void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs;
......
......@@ -22,6 +22,7 @@
#include <linux/profile.h>
#include <linux/bootmem.h>
#include <linux/vmalloc.h>
#include <linux/ftrace.h>
#include <linux/cpu.h>
#include <linux/slab.h>
......@@ -823,13 +824,13 @@ void arch_send_call_function_single_ipi(int cpu)
&cpumask_of_cpu(cpu));
}
void smp_call_function_client(int irq, struct pt_regs *regs)
void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
generic_smp_call_function_interrupt();
}
void smp_call_function_single_client(int irq, struct pt_regs *regs)
void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
generic_smp_call_function_single_interrupt();
......@@ -965,7 +966,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
put_cpu();
}
void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
{
struct mm_struct *mm;
unsigned long flags;
......@@ -1149,7 +1150,7 @@ void smp_release(void)
*/
extern void prom_world(int);
void smp_penguin_jailcell(int irq, struct pt_regs *regs)
void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
......@@ -1365,7 +1366,7 @@ void smp_send_reschedule(int cpu)
&cpumask_of_cpu(cpu));
}
void smp_receive_signal_client(int irq, struct pt_regs *regs)
void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
}
......
......@@ -35,6 +35,7 @@
#include <linux/clocksource.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/ftrace.h>
#include <asm/oplib.h>
#include <asm/timer.h>
......@@ -717,7 +718,7 @@ static struct clock_event_device sparc64_clockevent = {
};
static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
void timer_interrupt(int irq, struct pt_regs *regs)
void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long tick_mask = tick_ops->softint_mask;
......@@ -728,6 +729,7 @@ void timer_interrupt(int irq, struct pt_regs *regs)
irq_enter();
local_cpu_data().irq0_irqs++;
kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
if (unlikely(!evt->event_handler)) {
......
......@@ -2203,27 +2203,6 @@ void dump_stack(void)
EXPORT_SYMBOL(dump_stack);
static inline int is_kernel_stack(struct task_struct *task,
struct reg_window *rw)
{
unsigned long rw_addr = (unsigned long) rw;
unsigned long thread_base, thread_end;
if (rw_addr < PAGE_OFFSET) {
if (task != &init_task)
return 0;
}
thread_base = (unsigned long) task_stack_page(task);
thread_end = thread_base + sizeof(union thread_union);
if (rw_addr >= thread_base &&
rw_addr < thread_end &&
!(rw_addr & 0x7UL))
return 1;
return 0;
}
static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
{
unsigned long fp = rw->ins[6];
......@@ -2252,6 +2231,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
show_regs(regs);
add_taint(TAINT_DIE);
if (regs->tstate & TSTATE_PRIV) {
struct thread_info *tp = current_thread_info();
struct reg_window *rw = (struct reg_window *)
(regs->u_regs[UREG_FP] + STACK_BIAS);
......@@ -2259,8 +2239,8 @@ void die_if_kernel(char *str, struct pt_regs *regs)
* find some badly aligned kernel stack.
*/
while (rw &&
count++ < 30&&
is_kernel_stack(current, rw)) {
count++ < 30 &&
kstack_valid(tp, (unsigned long) rw)) {
printk("Caller[%016lx]: %pS\n", rw->ins[7],
(void *) rw->ins[7]);
......
......@@ -46,11 +46,16 @@ SECTIONS
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
IRQENTRY_TEXT
*(.gnu.warning)
} = 0
_etext = .;
RO_DATA(PAGE_SIZE)
/* Start of data section */
_sdata = .;
.data1 : {
*(.data1)
}
......
......@@ -7,26 +7,11 @@
#include <linux/linkage.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
/*
* This is the main variant and is called by C code. GCC's -pg option
* automatically instruments every C function with a call to this.
*/
#ifdef CONFIG_STACK_DEBUG
#define OVSTACKSIZE 4096 /* lets hope this is enough */
.data
.align 8
panicstring:
.asciz "Stack overflow\n"
.align 8
ovstack:
.skip OVSTACKSIZE
#endif
.text
.align 32
.globl _mcount
......@@ -35,84 +20,48 @@ ovstack:
.type mcount,#function
_mcount:
mcount:
#ifdef CONFIG_STACK_DEBUG
/*
* Check whether %sp is dangerously low.
*/
ldub [%g6 + TI_FPDEPTH], %g1
srl %g1, 1, %g3
add %g3, 1, %g3
sllx %g3, 8, %g3 ! each fpregs frame is 256b
add %g3, 192, %g3
add %g6, %g3, %g3 ! where does task_struct+frame end?
sub %g3, STACK_BIAS, %g3
cmp %sp, %g3
bg,pt %xcc, 1f
nop
lduh [%g6 + TI_CPU], %g1
sethi %hi(hardirq_stack), %g3
or %g3, %lo(hardirq_stack), %g3
sllx %g1, 3, %g1
ldx [%g3 + %g1], %g7
sub %g7, STACK_BIAS, %g7
cmp %sp, %g7
bleu,pt %xcc, 2f
sethi %hi(THREAD_SIZE), %g3
add %g7, %g3, %g7
cmp %sp, %g7
blu,pn %xcc, 1f
2: sethi %hi(softirq_stack), %g3
or %g3, %lo(softirq_stack), %g3
ldx [%g3 + %g1], %g7
sub %g7, STACK_BIAS, %g7
cmp %sp, %g7
bleu,pt %xcc, 3f
sethi %hi(THREAD_SIZE), %g3
add %g7, %g3, %g7
cmp %sp, %g7
blu,pn %xcc, 1f
nop
/* If we are already on ovstack, don't hop onto it
* again, we are already trying to output the stack overflow
* message.
*/
3: sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough
or %g7, %lo(ovstack), %g7
add %g7, OVSTACKSIZE, %g3
sub %g3, STACK_BIAS + 192, %g3
sub %g7, STACK_BIAS, %g7
cmp %sp, %g7
blu,pn %xcc, 2f
cmp %sp, %g3
bleu,pn %xcc, 1f
nop
2: mov %g3, %sp
sethi %hi(panicstring), %g3
call prom_printf
or %g3, %lo(panicstring), %o0
call prom_halt
nop
1:
#endif
#ifdef CONFIG_FUNCTION_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
mov %o7, %o0
.globl mcount_call
mcount_call:
call ftrace_stub
mov %o0, %o7
/* Do nothing, the retl/nop below is all we need. */
#else
sethi %hi(ftrace_trace_function), %g1
sethi %hi(function_trace_stop), %g1
lduw [%g1 + %lo(function_trace_stop)], %g2
brnz,pn %g2, 2f
sethi %hi(ftrace_trace_function), %g1
sethi %hi(ftrace_stub), %g2
ldx [%g1 + %lo(ftrace_trace_function)], %g1
or %g2, %lo(ftrace_stub), %g2
cmp %g1, %g2
be,pn %icc, 1f
mov %i7, %o1
jmpl %g1, %g0
mov %o7, %o0
mov %i7, %g3
save %sp, -128, %sp
mov %g3, %o1
jmpl %g1, %o7
mov %i7, %o0
ret
restore
/* not reached */
1:
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
sethi %hi(ftrace_graph_return), %g1
ldx [%g1 + %lo(ftrace_graph_return)], %g3
cmp %g2, %g3
bne,pn %xcc, 5f
sethi %hi(ftrace_graph_entry_stub), %g2
sethi %hi(ftrace_graph_entry), %g1
or %g2, %lo(ftrace_graph_entry_stub), %g2
ldx [%g1 + %lo(ftrace_graph_entry)], %g1
cmp %g1, %g2
be,pt %xcc, 2f
nop
5: mov %i7, %g2
mov %fp, %g3
save %sp, -128, %sp
mov %g2, %l0
ba,pt %xcc, ftrace_graph_caller
mov %g3, %l1
#endif
2:
#endif
#endif
retl
......@@ -131,14 +80,50 @@ ftrace_stub:
.globl ftrace_caller
.type ftrace_caller,#function
ftrace_caller:
mov %i7, %o1
mov %o7, %o0
sethi %hi(function_trace_stop), %g1
mov %i7, %g2
lduw [%g1 + %lo(function_trace_stop)], %g1
brnz,pn %g1, ftrace_stub
mov %fp, %g3
save %sp, -128, %sp
mov %g2, %o1
mov %g2, %l0
mov %g3, %l1
.globl ftrace_call
ftrace_call:
call ftrace_stub
mov %o0, %o7
retl
mov %i7, %o0
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl ftrace_graph_call
ftrace_graph_call:
call ftrace_stub
nop
#endif
ret
restore
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.size ftrace_graph_call,.-ftrace_graph_call
#endif
.size ftrace_call,.-ftrace_call
.size ftrace_caller,.-ftrace_caller
#endif
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
mov %l0, %o0
mov %i7, %o1
call prepare_ftrace_return
mov %l1, %o2
ret
restore %o0, -8, %i7
END(ftrace_graph_caller)
ENTRY(return_to_handler)
save %sp, -128, %sp
call ftrace_return_to_handler
mov %fp, %o0
jmpl %o0 + 8, %g0
restore
END(return_to_handler)
#endif
......@@ -356,7 +356,7 @@ config SLUB_STATS
config DEBUG_KMEMLEAK
bool "Kernel memory leak detector"
depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
(X86 || ARM || PPC || S390 || SUPERH || MICROBLAZE)
(X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE)
select DEBUG_FS if SYSFS
select STACKTRACE if STACKTRACE_SUPPORT
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment