Commit 0e37d259 authored by David Gibson's avatar David Gibson Committed by Benjamin Herrenschmidt

powerpc/book3e: Use set_irq_regs() in the msgsnd/msgrcv IPI path

include/asm-generic/irq_regs.h declares per-cpu irq_regs variables and
get_irq_regs() and set_irq_regs() helper functions to maintain them.
These can be used to access the proper pt_regs structure related to the
current interrupt entry (if any).

In the powerpc arch code, this is used to maintain irq regs on
decrementer and external interrupt exceptions.  However, for the
doorbell exceptions used by the msgsnd/msgrcv IPI mechanism of newer
BookE CPUs, the irq_regs are not kept up to date.

In particular this means that xmon will not work properly on SMP,
because the secondary xmon instances started by IPI will blow up when
they cannot retrieve the irq regs.

This patch fixes the problem by adding calls to maintain the irq regs
across doorbell exceptions.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 89c81797
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <asm/dbell.h> #include <asm/dbell.h>
#include <asm/irq_regs.h>
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
struct doorbell_cpu_info { struct doorbell_cpu_info {
...@@ -63,17 +64,21 @@ void doorbell_message_pass(int target, int msg) ...@@ -63,17 +64,21 @@ void doorbell_message_pass(int target, int msg)
void doorbell_exception(struct pt_regs *regs) void doorbell_exception(struct pt_regs *regs)
{ {
struct pt_regs *old_regs = set_irq_regs(regs);
struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
int msg; int msg;
/* Warning: regs can be NULL when called from irq enable */ /* Warning: regs can be NULL when called from irq enable */
if (!info->messages || (num_online_cpus() < 2)) if (!info->messages || (num_online_cpus() < 2))
return; goto out;
for (msg = 0; msg < 4; msg++) for (msg = 0; msg < 4; msg++)
if (test_and_clear_bit(msg, &info->messages)) if (test_and_clear_bit(msg, &info->messages))
smp_message_recv(msg); smp_message_recv(msg);
out:
set_irq_regs(old_regs);
} }
#else /* CONFIG_SMP */ #else /* CONFIG_SMP */
......
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