diff options
Diffstat (limited to 'arch/powerpc/kernel/dbell.c')
-rw-r--r-- | arch/powerpc/kernel/dbell.c | 65 |
1 files changed, 8 insertions, 57 deletions
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 3307a52d797f..2cc451aaaca7 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c | |||
@@ -13,84 +13,35 @@ | |||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
15 | #include <linux/threads.h> | 15 | #include <linux/threads.h> |
16 | #include <linux/percpu.h> | 16 | #include <linux/hardirq.h> |
17 | 17 | ||
18 | #include <asm/dbell.h> | 18 | #include <asm/dbell.h> |
19 | #include <asm/irq_regs.h> | 19 | #include <asm/irq_regs.h> |
20 | 20 | ||
21 | #ifdef CONFIG_SMP | 21 | #ifdef CONFIG_SMP |
22 | struct doorbell_cpu_info { | ||
23 | unsigned long messages; /* current messages bits */ | ||
24 | unsigned int tag; /* tag value */ | ||
25 | }; | ||
26 | |||
27 | static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info); | ||
28 | |||
29 | void doorbell_setup_this_cpu(void) | 22 | void doorbell_setup_this_cpu(void) |
30 | { | 23 | { |
31 | struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); | 24 | unsigned long tag = mfspr(SPRN_PIR) & 0x3fff; |
32 | 25 | ||
33 | info->messages = 0; | 26 | smp_muxed_ipi_set_data(smp_processor_id(), tag); |
34 | info->tag = mfspr(SPRN_PIR) & 0x3fff; | ||
35 | } | 27 | } |
36 | 28 | ||
37 | void doorbell_message_pass(int target, int msg) | 29 | void doorbell_cause_ipi(int cpu, unsigned long data) |
38 | { | 30 | { |
39 | struct doorbell_cpu_info *info; | 31 | ppc_msgsnd(PPC_DBELL, 0, data); |
40 | int i; | ||
41 | |||
42 | if (target < NR_CPUS) { | ||
43 | info = &per_cpu(doorbell_cpu_info, target); | ||
44 | set_bit(msg, &info->messages); | ||
45 | ppc_msgsnd(PPC_DBELL, 0, info->tag); | ||
46 | } | ||
47 | else if (target == MSG_ALL_BUT_SELF) { | ||
48 | for_each_online_cpu(i) { | ||
49 | if (i == smp_processor_id()) | ||
50 | continue; | ||
51 | info = &per_cpu(doorbell_cpu_info, i); | ||
52 | set_bit(msg, &info->messages); | ||
53 | ppc_msgsnd(PPC_DBELL, 0, info->tag); | ||
54 | } | ||
55 | } | ||
56 | else { /* target == MSG_ALL */ | ||
57 | for_each_online_cpu(i) { | ||
58 | info = &per_cpu(doorbell_cpu_info, i); | ||
59 | set_bit(msg, &info->messages); | ||
60 | } | ||
61 | ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); | ||
62 | } | ||
63 | } | 32 | } |
64 | 33 | ||
65 | void doorbell_exception(struct pt_regs *regs) | 34 | void doorbell_exception(struct pt_regs *regs) |
66 | { | 35 | { |
67 | struct pt_regs *old_regs = set_irq_regs(regs); | 36 | struct pt_regs *old_regs = set_irq_regs(regs); |
68 | struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); | ||
69 | int msg; | ||
70 | 37 | ||
71 | /* Warning: regs can be NULL when called from irq enable */ | 38 | irq_enter(); |
72 | 39 | ||
73 | if (!info->messages || (num_online_cpus() < 2)) | 40 | smp_ipi_demux(); |
74 | goto out; | ||
75 | 41 | ||
76 | for (msg = 0; msg < 4; msg++) | 42 | irq_exit(); |
77 | if (test_and_clear_bit(msg, &info->messages)) | ||
78 | smp_message_recv(msg); | ||
79 | |||
80 | out: | ||
81 | set_irq_regs(old_regs); | 43 | set_irq_regs(old_regs); |
82 | } | 44 | } |
83 | |||
84 | void doorbell_check_self(void) | ||
85 | { | ||
86 | struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); | ||
87 | |||
88 | if (!info->messages) | ||
89 | return; | ||
90 | |||
91 | ppc_msgsnd(PPC_DBELL, 0, info->tag); | ||
92 | } | ||
93 | |||
94 | #else /* CONFIG_SMP */ | 45 | #else /* CONFIG_SMP */ |
95 | void doorbell_exception(struct pt_regs *regs) | 46 | void doorbell_exception(struct pt_regs *regs) |
96 | { | 47 | { |