diff options
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/dbell.c | 46 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 94 |
3 files changed, 73 insertions, 71 deletions
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index e49b24c84133..2cc451aaaca7 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c | |||
@@ -13,65 +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 cpu, 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 | |||
41 | info = &per_cpu(doorbell_cpu_info, cpu); | ||
42 | set_bit(msg, &info->messages); | ||
43 | ppc_msgsnd(PPC_DBELL, 0, info->tag); | ||
44 | } | 32 | } |
45 | 33 | ||
46 | void doorbell_exception(struct pt_regs *regs) | 34 | void doorbell_exception(struct pt_regs *regs) |
47 | { | 35 | { |
48 | struct pt_regs *old_regs = set_irq_regs(regs); | 36 | struct pt_regs *old_regs = set_irq_regs(regs); |
49 | struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); | ||
50 | int msg; | ||
51 | 37 | ||
52 | /* Warning: regs can be NULL when called from irq enable */ | 38 | irq_enter(); |
53 | 39 | ||
54 | if (!info->messages || (num_online_cpus() < 2)) | 40 | smp_ipi_demux(); |
55 | goto out; | ||
56 | 41 | ||
57 | for (msg = 0; msg < 4; msg++) | 42 | irq_exit(); |
58 | if (test_and_clear_bit(msg, &info->messages)) | ||
59 | smp_message_recv(msg); | ||
60 | |||
61 | out: | ||
62 | set_irq_regs(old_regs); | 43 | set_irq_regs(old_regs); |
63 | } | 44 | } |
64 | |||
65 | void doorbell_check_self(void) | ||
66 | { | ||
67 | struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info); | ||
68 | |||
69 | if (!info->messages) | ||
70 | return; | ||
71 | |||
72 | ppc_msgsnd(PPC_DBELL, 0, info->tag); | ||
73 | } | ||
74 | |||
75 | #else /* CONFIG_SMP */ | 45 | #else /* CONFIG_SMP */ |
76 | void doorbell_exception(struct pt_regs *regs) | 46 | void doorbell_exception(struct pt_regs *regs) |
77 | { | 47 | { |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index a81dd74414bf..826552cecebd 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -66,7 +66,6 @@ | |||
66 | #include <asm/ptrace.h> | 66 | #include <asm/ptrace.h> |
67 | #include <asm/machdep.h> | 67 | #include <asm/machdep.h> |
68 | #include <asm/udbg.h> | 68 | #include <asm/udbg.h> |
69 | #include <asm/dbell.h> | ||
70 | #include <asm/smp.h> | 69 | #include <asm/smp.h> |
71 | 70 | ||
72 | #ifdef CONFIG_PPC64 | 71 | #ifdef CONFIG_PPC64 |
@@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en) | |||
160 | 159 | ||
161 | #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) | 160 | #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP) |
162 | /* Check for pending doorbell interrupts and resend to ourself */ | 161 | /* Check for pending doorbell interrupts and resend to ourself */ |
163 | doorbell_check_self(); | 162 | if (cpu_has_feature(CPU_FTR_DBELL)) |
163 | smp_muxed_ipi_resend(); | ||
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | /* | 166 | /* |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index b74411446922..fa8e8700064b 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -111,35 +111,6 @@ int __devinit smp_generic_kick_cpu(int nr) | |||
111 | } | 111 | } |
112 | #endif | 112 | #endif |
113 | 113 | ||
114 | void smp_message_recv(int msg) | ||
115 | { | ||
116 | switch(msg) { | ||
117 | case PPC_MSG_CALL_FUNCTION: | ||
118 | generic_smp_call_function_interrupt(); | ||
119 | break; | ||
120 | case PPC_MSG_RESCHEDULE: | ||
121 | /* we notice need_resched on exit */ | ||
122 | break; | ||
123 | case PPC_MSG_CALL_FUNC_SINGLE: | ||
124 | generic_smp_call_function_single_interrupt(); | ||
125 | break; | ||
126 | case PPC_MSG_DEBUGGER_BREAK: | ||
127 | if (crash_ipi_function_ptr) { | ||
128 | crash_ipi_function_ptr(get_irq_regs()); | ||
129 | break; | ||
130 | } | ||
131 | #ifdef CONFIG_DEBUGGER | ||
132 | debugger_ipi(get_irq_regs()); | ||
133 | break; | ||
134 | #endif /* CONFIG_DEBUGGER */ | ||
135 | /* FALLTHROUGH */ | ||
136 | default: | ||
137 | printk("SMP %d: smp_message_recv(): unknown msg %d\n", | ||
138 | smp_processor_id(), msg); | ||
139 | break; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | static irqreturn_t call_function_action(int irq, void *data) | 114 | static irqreturn_t call_function_action(int irq, void *data) |
144 | { | 115 | { |
145 | generic_smp_call_function_interrupt(); | 116 | generic_smp_call_function_interrupt(); |
@@ -158,9 +129,17 @@ static irqreturn_t call_function_single_action(int irq, void *data) | |||
158 | return IRQ_HANDLED; | 129 | return IRQ_HANDLED; |
159 | } | 130 | } |
160 | 131 | ||
161 | static irqreturn_t debug_ipi_action(int irq, void *data) | 132 | irqreturn_t debug_ipi_action(int irq, void *data) |
162 | { | 133 | { |
163 | smp_message_recv(PPC_MSG_DEBUGGER_BREAK); | 134 | if (crash_ipi_function_ptr) { |
135 | crash_ipi_function_ptr(get_irq_regs()); | ||
136 | return IRQ_HANDLED; | ||
137 | } | ||
138 | |||
139 | #ifdef CONFIG_DEBUGGER | ||
140 | debugger_ipi(get_irq_regs()); | ||
141 | #endif /* CONFIG_DEBUGGER */ | ||
142 | |||
164 | return IRQ_HANDLED; | 143 | return IRQ_HANDLED; |
165 | } | 144 | } |
166 | 145 | ||
@@ -199,6 +178,59 @@ int smp_request_message_ipi(int virq, int msg) | |||
199 | return err; | 178 | return err; |
200 | } | 179 | } |
201 | 180 | ||
181 | struct cpu_messages { | ||
182 | unsigned long messages; /* current messages bits */ | ||
183 | unsigned long data; /* data for cause ipi */ | ||
184 | }; | ||
185 | static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message); | ||
186 | |||
187 | void smp_muxed_ipi_set_data(int cpu, unsigned long data) | ||
188 | { | ||
189 | struct cpu_messages *info = &per_cpu(ipi_message, cpu); | ||
190 | |||
191 | info->data = data; | ||
192 | } | ||
193 | |||
194 | void smp_muxed_ipi_message_pass(int cpu, int msg) | ||
195 | { | ||
196 | struct cpu_messages *info = &per_cpu(ipi_message, cpu); | ||
197 | unsigned long *tgt = &info->messages; | ||
198 | |||
199 | set_bit(msg, tgt); | ||
200 | mb(); | ||
201 | smp_ops->cause_ipi(cpu, info->data); | ||
202 | } | ||
203 | |||
204 | void smp_muxed_ipi_resend(void) | ||
205 | { | ||
206 | struct cpu_messages *info = &__get_cpu_var(ipi_message); | ||
207 | unsigned long *tgt = &info->messages; | ||
208 | |||
209 | if (*tgt) | ||
210 | smp_ops->cause_ipi(smp_processor_id(), info->data); | ||
211 | } | ||
212 | |||
213 | irqreturn_t smp_ipi_demux(void) | ||
214 | { | ||
215 | struct cpu_messages *info = &__get_cpu_var(ipi_message); | ||
216 | unsigned long *tgt = &info->messages; | ||
217 | |||
218 | mb(); /* order any irq clear */ | ||
219 | while (*tgt) { | ||
220 | if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) | ||
221 | generic_smp_call_function_interrupt(); | ||
222 | if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) | ||
223 | reschedule_action(0, NULL); /* upcoming sched hook */ | ||
224 | if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) | ||
225 | generic_smp_call_function_single_interrupt(); | ||
226 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | ||
227 | if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) | ||
228 | debug_ipi_action(0, NULL); | ||
229 | #endif | ||
230 | } | ||
231 | return IRQ_HANDLED; | ||
232 | } | ||
233 | |||
202 | void smp_send_reschedule(int cpu) | 234 | void smp_send_reschedule(int cpu) |
203 | { | 235 | { |
204 | if (likely(smp_ops)) | 236 | if (likely(smp_ops)) |