| From 238e8427818fe23150a52141641fecfa0591761d Mon Sep 17 00:00:00 2001 |
| From: David S. Miller <davem@davemloft.net> |
| Date: Mon, 10 May 2010 05:19:10 -0700 |
| Subject: sparc64: Adjust __raw_local_irq_save() to cooperate in NMIs. |
| |
| |
| From: David S. Miller <davem@davemloft.net> |
| |
| [ Upstream commits 0c25e9e6cbe7b233bb91d14d0e2c258bf8e6ec83 and |
| c011f80ba0912486fe51dd2b3f71d9b33a151188 ] |
| |
| If we are in an NMI then doing a plain raw_local_irq_disable() will |
| write PIL_NORMAL_MAX into %pil, which is lower than PIL_NMI, and thus |
| we'll re-enable NMIs and recurse. |
| |
| Doing a simple: |
| |
| %pil = %pil | PIL_NORMAL_MAX |
| |
| does what we want, if we're already at PIL_NMI (15) we leave it at |
| that setting, else we set it to PIL_NORMAL_MAX (14). |
| |
| This should get the function tracer working on sparc64. |
| |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| arch/sparc/include/asm/irqflags_64.h | 21 +++++++++++++++++++-- |
| 1 file changed, 19 insertions(+), 2 deletions(-) |
| |
| --- a/arch/sparc/include/asm/irqflags_64.h |
| +++ b/arch/sparc/include/asm/irqflags_64.h |
| @@ -76,9 +76,26 @@ static inline int raw_irqs_disabled(void |
| */ |
| static inline unsigned long __raw_local_irq_save(void) |
| { |
| - unsigned long flags = __raw_local_save_flags(); |
| + unsigned long flags, tmp; |
| |
| - raw_local_irq_disable(); |
| + /* Disable interrupts to PIL_NORMAL_MAX unless we already |
| + * are using PIL_NMI, in which case PIL_NMI is retained. |
| + * |
| + * The only values we ever program into the %pil are 0, |
| + * PIL_NORMAL_MAX and PIL_NMI. |
| + * |
| + * Since PIL_NMI is the largest %pil value and all bits are |
| + * set in it (0xf), it doesn't matter what PIL_NORMAL_MAX |
| + * actually is. |
| + */ |
| + __asm__ __volatile__( |
| + "rdpr %%pil, %0\n\t" |
| + "or %0, %2, %1\n\t" |
| + "wrpr %1, 0x0, %%pil" |
| + : "=r" (flags), "=r" (tmp) |
| + : "i" (PIL_NORMAL_MAX) |
| + : "memory" |
| + ); |
| |
| return flags; |
| } |