Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ff82850 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6:
  sparc64: Handle stack trace attempts before irqstacks are setup.
  sparc64: Implement IRQ stacks.
  sparc: remove include of linux/of_device.h from asm/of_device.h
  sparc64: Fix recursion in stack overflow detection handling.
  sparc/drivers: use linux/of_device.h instead of asm/of_device.h
  sparc64: Don't MAGIC_SYSRQ ifdef smp_fetch_global_regs and support code.
parents 8d0968ab 6f63e781
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -93,4 +93,8 @@ static inline unsigned long get_softint(void)
void __trigger_all_cpu_backtrace(void);
#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()

extern void *hardirq_stack[NR_CPUS];
extern void *softirq_stack[NR_CPUS];
#define __ARCH_HAS_DO_SOFTIRQ

#endif
+1 −2
Original line number Diff line number Diff line
@@ -30,8 +30,7 @@ struct of_device
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);

/* These are just here during the transition */
#include <linux/of_device.h>
/* This is just here during the transition */
#include <linux/of_platform.h>

#endif /* __KERNEL__ */
+52 −0
Original line number Diff line number Diff line
@@ -682,10 +682,32 @@ void ack_bad_irq(unsigned int virt_irq)
	       ino, virt_irq);
}

void *hardirq_stack[NR_CPUS];
void *softirq_stack[NR_CPUS];

static __attribute__((always_inline)) void *set_hardirq_stack(void)
{
	void *orig_sp, *sp = hardirq_stack[smp_processor_id()];

	__asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp));
	if (orig_sp < sp ||
	    orig_sp > (sp + THREAD_SIZE)) {
		sp += THREAD_SIZE - 192 - STACK_BIAS;
		__asm__ __volatile__("mov %0, %%sp" : : "r" (sp));
	}

	return orig_sp;
}
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)
{
	unsigned long pstate, bucket_pa;
	struct pt_regs *old_regs;
	void *orig_sp;

	clear_softint(1 << irq);

@@ -703,6 +725,8 @@ void handler_irq(int irq, struct pt_regs *regs)
			       "i" (PSTATE_IE)
			     : "memory");

	orig_sp = set_hardirq_stack();

	while (bucket_pa) {
		struct irq_desc *desc;
		unsigned long next_pa;
@@ -719,10 +743,38 @@ void handler_irq(int irq, struct pt_regs *regs)
		bucket_pa = next_pa;
	}

	restore_hardirq_stack(orig_sp);

	irq_exit();
	set_irq_regs(old_regs);
}

void do_softirq(void)
{
	unsigned long flags;

	if (in_interrupt())
		return;

	local_irq_save(flags);

	if (local_softirq_pending()) {
		void *orig_sp, *sp = softirq_stack[smp_processor_id()];

		sp += THREAD_SIZE - 192 - STACK_BIAS;

		__asm__ __volatile__("mov %%sp, %0\n\t"
				     "mov %1, %%sp"
				     : "=&r" (orig_sp)
				     : "r" (sp));
		__do_softirq();
		__asm__ __volatile__("mov %0, %%sp"
				     : : "r" (orig_sp));
	}

	local_irq_restore(flags);
}

#ifdef CONFIG_HOTPLUG_CPU
void fixup_irqs(void)
{
+60 −0
Original line number Diff line number Diff line
#ifndef _KSTACK_H
#define _KSTACK_H

#include <linux/thread_info.h>
#include <linux/sched.h>
#include <asm/ptrace.h>
#include <asm/irq.h>

/* SP must be STACK_BIAS adjusted already.  */
static inline bool kstack_valid(struct thread_info *tp, unsigned long sp)
{
	unsigned long base = (unsigned long) tp;

	if (sp >= (base + sizeof(struct thread_info)) &&
	    sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
		return true;

	if (hardirq_stack[tp->cpu]) {
		base = (unsigned long) hardirq_stack[tp->cpu];
		if (sp >= base &&
		    sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
			return true;
		base = (unsigned long) softirq_stack[tp->cpu];
		if (sp >= base &&
		    sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
			return true;
	}
	return false;
}

/* Does "regs" point to a valid pt_regs trap frame?  */
static inline bool kstack_is_trap_frame(struct thread_info *tp, struct pt_regs *regs)
{
	unsigned long base = (unsigned long) tp;
	unsigned long addr = (unsigned long) regs;

	if (addr >= base &&
	    addr <= (base + THREAD_SIZE - sizeof(*regs)))
		goto check_magic;

	if (hardirq_stack[tp->cpu]) {
		base = (unsigned long) hardirq_stack[tp->cpu];
		if (addr >= base &&
		    addr <= (base + THREAD_SIZE - sizeof(*regs)))
			goto check_magic;
		base = (unsigned long) softirq_stack[tp->cpu];
		if (addr >= base &&
		    addr <= (base + THREAD_SIZE - sizeof(*regs)))
			goto check_magic;
	}
	return false;

check_magic:
	if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC)
		return true;
	return false;

}

#endif /* _KSTACK_H */
+7 −20
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@
#include <asm/irq_regs.h>
#include <asm/smp.h>

#include "kstack.h"

static void sparc64_yield(int cpu)
{
	if (tlb_type != hypervisor)
@@ -235,19 +237,6 @@ void show_regs(struct pt_regs *regs)
struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
static DEFINE_SPINLOCK(global_reg_snapshot_lock);

static bool kstack_valid(struct thread_info *tp, struct reg_window *rw)
{
	unsigned long thread_base, fp;

	thread_base = (unsigned long) tp;
	fp = (unsigned long) rw;

	if (fp < (thread_base + sizeof(struct thread_info)) ||
	    fp >= (thread_base + THREAD_SIZE))
		return false;
	return true;
}

static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
			      int this_cpu)
{
@@ -264,11 +253,11 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,

		rw = (struct reg_window *)
			(regs->u_regs[UREG_FP] + STACK_BIAS);
		if (kstack_valid(tp, rw)) {
		if (kstack_valid(tp, (unsigned long) rw)) {
			global_reg_snapshot[this_cpu].i7 = rw->ins[7];
			rw = (struct reg_window *)
				(rw->ins[6] + STACK_BIAS);
			if (kstack_valid(tp, rw))
			if (kstack_valid(tp, (unsigned long) rw))
				global_reg_snapshot[this_cpu].rpc = rw->ins[7];
		}
	} else {
@@ -828,7 +817,7 @@ out:
unsigned long get_wchan(struct task_struct *task)
{
	unsigned long pc, fp, bias = 0;
	unsigned long thread_info_base;
	struct thread_info *tp;
	struct reg_window *rw;
        unsigned long ret = 0;
	int count = 0; 
@@ -837,14 +826,12 @@ unsigned long get_wchan(struct task_struct *task)
            task->state == TASK_RUNNING)
		goto out;

	thread_info_base = (unsigned long) task_stack_page(task);
	tp = task_thread_info(task);
	bias = STACK_BIAS;
	fp = task_thread_info(task)->ksp + bias;

	do {
		/* Bogus frame pointer? */
		if (fp < (thread_info_base + sizeof(struct thread_info)) ||
		    fp >= (thread_info_base + THREAD_SIZE))
		if (!kstack_valid(tp, fp))
			break;
		rw = (struct reg_window *) fp;
		pc = rw->ins[7];
Loading