Skip to content

Commit 69ea03b

Browse files
Peter ZijlstraKAGA-KOKO
authored andcommitted
hardirq/nmi: Allow nested nmi_enter()
Since there are already a number of sites (ARM64, PowerPC) that effectively nest nmi_enter(), make the primitive support this before adding even more. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Marc Zyngier <[email protected]> Acked-by: Will Deacon <[email protected]> Cc: Michael Ellerman <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 28f6bf9 commit 69ea03b

File tree

5 files changed

+16
-37
lines changed

5 files changed

+16
-37
lines changed

arch/arm64/kernel/sdei.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -251,22 +251,12 @@ asmlinkage __kprobes notrace unsigned long
251251
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
252252
{
253253
unsigned long ret;
254-
bool do_nmi_exit = false;
255254

256-
/*
257-
* nmi_enter() deals with printk() re-entrance and use of RCU when
258-
* RCU believed this CPU was idle. Because critical events can
259-
* interrupt normal events, we may already be in_nmi().
260-
*/
261-
if (!in_nmi()) {
262-
nmi_enter();
263-
do_nmi_exit = true;
264-
}
255+
nmi_enter();
265256

266257
ret = _sdei_handler(regs, arg);
267258

268-
if (do_nmi_exit)
269-
nmi_exit();
259+
nmi_exit();
270260

271261
return ret;
272262
}

arch/arm64/kernel/traps.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -906,17 +906,13 @@ bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr)
906906

907907
asmlinkage void do_serror(struct pt_regs *regs, unsigned int esr)
908908
{
909-
const bool was_in_nmi = in_nmi();
910-
911-
if (!was_in_nmi)
912-
nmi_enter();
909+
nmi_enter();
913910

914911
/* non-RAS errors are not containable */
915912
if (!arm64_is_ras_serror(esr) || arm64_is_fatal_ras_serror(regs, esr))
916913
arm64_serror_panic(regs, esr);
917914

918-
if (!was_in_nmi)
919-
nmi_exit();
915+
nmi_exit();
920916
}
921917

922918
asmlinkage void enter_from_user_mode(void)

arch/powerpc/kernel/traps.c

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -441,15 +441,9 @@ void hv_nmi_check_nonrecoverable(struct pt_regs *regs)
441441
void system_reset_exception(struct pt_regs *regs)
442442
{
443443
unsigned long hsrr0, hsrr1;
444-
bool nested = in_nmi();
445444
bool saved_hsrrs = false;
446445

447-
/*
448-
* Avoid crashes in case of nested NMI exceptions. Recoverability
449-
* is determined by RI and in_nmi
450-
*/
451-
if (!nested)
452-
nmi_enter();
446+
nmi_enter();
453447

454448
/*
455449
* System reset can interrupt code where HSRRs are live and MSR[RI]=1.
@@ -521,8 +515,7 @@ void system_reset_exception(struct pt_regs *regs)
521515
mtspr(SPRN_HSRR1, hsrr1);
522516
}
523517

524-
if (!nested)
525-
nmi_exit();
518+
nmi_exit();
526519

527520
/* What should we do here? We could issue a shutdown or hard reset. */
528521
}
@@ -823,9 +816,8 @@ int machine_check_generic(struct pt_regs *regs)
823816
void machine_check_exception(struct pt_regs *regs)
824817
{
825818
int recover = 0;
826-
bool nested = in_nmi();
827-
if (!nested)
828-
nmi_enter();
819+
820+
nmi_enter();
829821

830822
__this_cpu_inc(irq_stat.mce_exceptions);
831823

@@ -851,8 +843,7 @@ void machine_check_exception(struct pt_regs *regs)
851843
if (check_io_access(regs))
852844
goto bail;
853845

854-
if (!nested)
855-
nmi_exit();
846+
nmi_exit();
856847

857848
die("Machine check", regs, SIGBUS);
858849

@@ -863,8 +854,7 @@ void machine_check_exception(struct pt_regs *regs)
863854
return;
864855

865856
bail:
866-
if (!nested)
867-
nmi_exit();
857+
nmi_exit();
868858
}
869859

870860
void SMIException(struct pt_regs *regs)

include/linux/hardirq.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,16 @@ extern void irq_exit(void);
6565
#define arch_nmi_exit() do { } while (0)
6666
#endif
6767

68+
/*
69+
* nmi_enter() can nest up to 15 times; see NMI_BITS.
70+
*/
6871
#define nmi_enter() \
6972
do { \
7073
arch_nmi_enter(); \
7174
printk_nmi_enter(); \
7275
lockdep_off(); \
7376
ftrace_nmi_enter(); \
74-
BUG_ON(in_nmi()); \
77+
BUG_ON(in_nmi() == NMI_MASK); \
7578
preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
7679
rcu_nmi_enter(); \
7780
lockdep_hardirq_enter(); \

include/linux/preempt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
* PREEMPT_MASK: 0x000000ff
2727
* SOFTIRQ_MASK: 0x0000ff00
2828
* HARDIRQ_MASK: 0x000f0000
29-
* NMI_MASK: 0x00100000
29+
* NMI_MASK: 0x00f00000
3030
* PREEMPT_NEED_RESCHED: 0x80000000
3131
*/
3232
#define PREEMPT_BITS 8
3333
#define SOFTIRQ_BITS 8
3434
#define HARDIRQ_BITS 4
35-
#define NMI_BITS 1
35+
#define NMI_BITS 4
3636

3737
#define PREEMPT_SHIFT 0
3838
#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)

0 commit comments

Comments
 (0)