summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/dbell.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-05 09:03:46 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-05 09:03:46 -0700
commitcdd854bc42b5e6c79bbbc40c6600d995ffe6e747 (patch)
tree18c4dcc07bbb8aeb2b23bc812cd60cc293f36cd8 /arch/powerpc/kernel/dbell.c
parentbbc4fd12a635492ad9d12bb418124fa2d5f0d734 (diff)
parent42a0ae2282b512d1a8f6f020327f5f7b8f31a5ea (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (79 commits) powerpc/8xx: Add support for the MPC8xx based boards from TQC powerpc/85xx: Introduce support for the Freescale P1022DS reference board powerpc/85xx: Adding DTS for the STx GP3-SSA MPC8555 board powerpc/85xx: Change deprecated binding for 85xx-based boards powerpc/tqm85xx: add a quirk for ti1520 PCMCIA bridge powerpc/tqm85xx: update PCI interrupt-map attribute powerpc/mpc8308rdb: support for MPC8308RDB board from Freescale powerpc/fsl_pci: add quirk for mpc8308 pcie bridge powerpc/85xx: Cleanup QE initialization for MPC85xxMDS boards powerpc/85xx: Fix booting for P1021MDS boards powerpc/85xx: Fix SWIOTLB initalization for MPC85xxMDS boards powerpc/85xx: kexec for SMP 85xx BookE systems powerpc/5200/i2c: improve i2c bus error recovery of/xilinxfb: update tft compatible versions powerpc/fsl-diu-fb: Support setting display mode using EDID powerpc/5121: doc/dts-bindings: update doc of FSL DIU bindings powerpc/5121: shared DIU framebuffer support powerpc/5121: move fsl-diu-fb.h to include/linux powerpc/5121: fsl-diu-fb: fix issue with re-enabling DIU area descriptor powerpc/512x: add clock structure for Video-IN (VIU) unit ...
Diffstat (limited to 'arch/powerpc/kernel/dbell.c')
-rw-r--r--arch/powerpc/kernel/dbell.c78
1 files changed, 67 insertions, 11 deletions
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index 1493734cd871..3307a52d797f 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -13,32 +13,88 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/threads.h>
+#include <linux/percpu.h>
#include <asm/dbell.h>
+#include <asm/irq_regs.h>
#ifdef CONFIG_SMP
-unsigned long dbell_smp_message[NR_CPUS];
+struct doorbell_cpu_info {
+ unsigned long messages; /* current messages bits */
+ unsigned int tag; /* tag value */
+};
-void smp_dbell_message_pass(int target, int msg)
+static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info);
+
+void doorbell_setup_this_cpu(void)
+{
+ struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+
+ info->messages = 0;
+ info->tag = mfspr(SPRN_PIR) & 0x3fff;
+}
+
+void doorbell_message_pass(int target, int msg)
{
+ struct doorbell_cpu_info *info;
int i;
- if(target < NR_CPUS) {
- set_bit(msg, &dbell_smp_message[target]);
- ppc_msgsnd(PPC_DBELL, 0, target);
+ if (target < NR_CPUS) {
+ info = &per_cpu(doorbell_cpu_info, target);
+ set_bit(msg, &info->messages);
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
}
- else if(target == MSG_ALL_BUT_SELF) {
+ else if (target == MSG_ALL_BUT_SELF) {
for_each_online_cpu(i) {
if (i == smp_processor_id())
continue;
- set_bit(msg, &dbell_smp_message[i]);
- ppc_msgsnd(PPC_DBELL, 0, i);
+ info = &per_cpu(doorbell_cpu_info, i);
+ set_bit(msg, &info->messages);
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
}
}
else { /* target == MSG_ALL */
- for_each_online_cpu(i)
- set_bit(msg, &dbell_smp_message[i]);
+ for_each_online_cpu(i) {
+ info = &per_cpu(doorbell_cpu_info, i);
+ set_bit(msg, &info->messages);
+ }
ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
}
}
-#endif
+
+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);
+ int msg;
+
+ /* Warning: regs can be NULL when called from irq enable */
+
+ if (!info->messages || (num_online_cpus() < 2))
+ goto out;
+
+ for (msg = 0; msg < 4; msg++)
+ if (test_and_clear_bit(msg, &info->messages))
+ smp_message_recv(msg);
+
+out:
+ set_irq_regs(old_regs);
+}
+
+void doorbell_check_self(void)
+{
+ struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+
+ if (!info->messages)
+ return;
+
+ ppc_msgsnd(PPC_DBELL, 0, info->tag);
+}
+
+#else /* CONFIG_SMP */
+void doorbell_exception(struct pt_regs *regs)
+{
+ printk(KERN_WARNING "Received doorbell on non-smp system\n");
+}
+#endif /* CONFIG_SMP */
+