x86: Remove cmpxchg from i386 NMI nesting code
commitc7d65a78fc18ed70353baeb7497ec71a7c775ac5
authorSteven Rostedt <srostedt@redhat.com>
Thu, 7 Jun 2012 15:03:00 +0000 (7 11:03 -0400)
committerSteven Rostedt <rostedt@goodmis.org>
Fri, 8 Jun 2012 22:48:05 +0000 (8 18:48 -0400)
tree1cf4651a56b972cbaa66361f41246d1e107548cd
parent7fbb98c5cb07563d3ee08714073a8e5452a96be2
x86: Remove cmpxchg from i386 NMI nesting code

I've been informed by someone on LWN called 'slashdot' that
some i386 machines do not support a true cmpxchg. The cmpxchg
used by the i386 NMI nesting code must be a true cmpxchg as
disabling interrupts will not work for NMIs (which is the work
around for i386s that do not have a true cmpxchg).

This 'slashdot' character also suggested a fix to the issue.
As the state of the nesting NMIs goes as follows:

  NOT_RUNNING -> EXECUTING
  EXECUTING   -> NOT_RUNNING
  EXECUTING   -> LATCHED
  LATCHED     -> EXECUTING

Having these states as enum values of:

  NOT_RUNNING = 0
  EXECUTING   = 1
  LATCHED     = 2

Instead of a cmpxchg to make EXECUTING -> NOT_RUNNING a
dec_and_test() would work as well. If the dec_and_test brings
the state to NOT_RUNNING, that is the same as a cmpxchg
succeeding to change EXECUTING to NOT_RUNNING. If a nested NMI
were to come in and change it to LATCHED, the dec_and_test() would
convert the state to EXECUTING (what we want it to be in such a
case anyway).

I asked 'slashdot' to post this as a patch, but it never came to
be. I decided to do the work instead.

Thanks to H. Peter Anvin for suggesting to use this_cpu_dec_and_return()
instead of local_dec_and_test(&__get_cpu_var()).

Link: http://lwn.net/Articles/484932/
Cc: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
arch/x86/kernel/nmi.c