diff options
author | Hugh Dickins <hugh@veritas.com> | 2006-11-10 21:32:40 +0000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-12-04 20:39:20 +1100 |
commit | ef2b343e99e772e35f0f9d00f7db318b6629c16e (patch) | |
tree | 386f9b6b1376ab99a478ab5d394572fca720d0ef /include | |
parent | 56291e19e37cf3bb8fc701ebf3aa8ffbf59f73ef (diff) | |
download | lwn-ef2b343e99e772e35f0f9d00f7db318b6629c16e.tar.gz lwn-ef2b343e99e772e35f0f9d00f7db318b6629c16e.zip |
[POWERPC] Make soft_enabled irqs preempt safe
Rewrite local_get_flags and local_irq_disable to use r13 explicitly,
to avoid the risk that gcc will split get_paca()->soft_enabled into a
sequence unsafe against preemption. Similar care in local_irq_restore.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-powerpc/hw_irq.h | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h index c4a1ab608f6f..fd3f2a206271 100644 --- a/include/asm-powerpc/hw_irq.h +++ b/include/asm-powerpc/hw_irq.h @@ -18,15 +18,25 @@ extern void timer_interrupt(struct pt_regs *); static inline unsigned long local_get_flags(void) { - return get_paca()->soft_enabled; + unsigned long flags; + + __asm__ __volatile__("lbz %0,%1(13)" + : "=r" (flags) + : "i" (offsetof(struct paca_struct, soft_enabled))); + + return flags; } static inline unsigned long local_irq_disable(void) { - unsigned long flag = get_paca()->soft_enabled; - get_paca()->soft_enabled = 0; - barrier(); - return flag; + unsigned long flags, zero; + + __asm__ __volatile__("li %1,0; lbz %0,%2(13); stb %1,%2(13)" + : "=r" (flags), "=&r" (zero) + : "i" (offsetof(struct paca_struct, soft_enabled)) + : "memory"); + + return flags; } extern void local_irq_restore(unsigned long); |