[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20091103171054.GB25437@redhat.com>
Date: Tue, 3 Nov 2009 12:10:54 -0500
From: Aristeu Rozanski <aris@...hat.com>
To: Ingo Molnar <mingo@...e.hu>
Cc: linux-kernel@...r.kernel.org
Subject: [PATCH 2/2] x86: introduce NMI_AUTO as nmi_watchdog option
NMI_AUTO is a new nmi_watchdog option that makes LAPIC be tried first and if
the CPU isn't supported, IOAPIC will be used. It's useful in cases where
NMI watchdog is enabled by default in a kernel built for different machines.
It can be configured by default or selected with nmi_watchdog=3 or
nmi_watchdog=auto parameters.
Signed-off-by: Aristeu Rozanski <aris@...hat.com>
---
Documentation/kernel-parameters.txt | 15 +++++++++------
Documentation/nmi_watchdog.txt | 4 +++-
arch/x86/include/asm/nmi.h | 5 ++++-
arch/x86/kernel/apic/apic.c | 1 +
arch/x86/kernel/apic/nmi.c | 21 +++++++++++++++++++++
arch/x86/kernel/cpu/perfctr-watchdog.c | 12 +++++++++---
lib/Kconfig.debug | 5 +++++
7 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 6d0a7c9..a3f382b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1520,19 +1520,22 @@ and is between 256 and 4096 characters. It is defined in the file
nmi_watchdog= [KNL,BUGS=X86] Debugging features for SMP kernels
Format: [panic,][num]
- Valid num: 0,1,2
+ Valid num: 0,1,2,3
0 - turn nmi_watchdog off
1 - use the IO-APIC timer for the NMI watchdog
2 - use the local APIC for the NMI watchdog using
- a performance counter. Note: This will use one
- performance counter and the local APIC's performance
- vector.
+ a performance counter. Note: This will use one
+ performance counter and the local APIC's performance
+ vector.
+ 3 - "auto" mode: first checks if the CPU is supported
+ by local APIC method and uses it in that case. If
+ it's not, IOAPIC is tried.
When panic is specified, panic when an NMI watchdog
timeout occurs.
This is useful when you use a panic=... timeout and
need the box quickly up again.
- Instead of 1 and 2 it is possible to use the following
- symbolic names: lapic and ioapic
+ Instead of 1, 2 and 3 it is possible to use the following
+ symbolic names: ioapic, lapic, auto
Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic
no387 [BUGS=X86-32] Tells the kernel to use the 387 maths
diff --git a/Documentation/nmi_watchdog.txt b/Documentation/nmi_watchdog.txt
index bf9f80a..3f163d2 100644
--- a/Documentation/nmi_watchdog.txt
+++ b/Documentation/nmi_watchdog.txt
@@ -40,7 +40,9 @@ for some processor types. If in doubt, boot with nmi_watchdog=1 and
check the NMI count in /proc/interrupts; if the count is zero then
reboot with nmi_watchdog=2 and check the NMI count. If it is still
zero then log a problem, you probably have a processor that needs to be
-added to the nmi code.
+added to the nmi code. Another option is using "auto" mode (nmi_watchdog=3
+or nmi_watchdog=auto). On "auto" mode, it's first verified if the CPU is
+supported by LAPIC mode and if it's not, IOAPIC method is used.
A 'lockup' is the following scenario: if any CPU in the system does not
execute the period local timer interrupt for more than 5 seconds, then
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index c86e5ed..231d4cb 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -25,6 +25,7 @@ extern void release_perfctr_nmi(unsigned int);
extern int reserve_evntsel_nmi(unsigned int);
extern void release_evntsel_nmi(unsigned int);
+extern void default_nmi_watchdog(void);
extern void setup_apic_nmi_watchdog(void *);
extern void stop_apic_nmi_watchdog(void *);
extern void disable_timer_nmi_watchdog(void);
@@ -37,7 +38,8 @@ extern unsigned int nmi_watchdog;
#define NMI_NONE 0
#define NMI_IO_APIC 1
#define NMI_LOCAL_APIC 2
-#define NMI_INVALID 3
+#define NMI_AUTO 3
+#define NMI_INVALID 4
struct ctl_table;
struct file;
@@ -69,6 +71,7 @@ static inline int nmi_watchdog_active(void)
#endif
void lapic_watchdog_stop(void);
+int lapic_watchdog_detect(void);
int lapic_watchdog_init(unsigned nmi_hz);
int lapic_wd_event(unsigned nmi_hz);
unsigned lapic_adjust_nmi_hz(unsigned hz);
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 0a1c283..f30972b 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1333,6 +1333,7 @@ void __cpuinit end_local_APIC_setup(void)
}
#endif
+ default_nmi_watchdog();
setup_apic_nmi_watchdog(NULL);
apic_pm_activate();
}
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c
index fd176e9..c157d4d 100644
--- a/arch/x86/kernel/apic/nmi.c
+++ b/arch/x86/kernel/apic/nmi.c
@@ -59,6 +59,9 @@ EXPORT_SYMBOL(nmi_active);
#ifdef CONFIG_DEBUG_DEFAULT_NMI_LAPIC
#define DEFAULT_NMI_WATCHDOG_VALUE NMI_LAPIC
#endif
+#ifdef CONFIG_DEBUG_DEFAULT_NMI_AUTO
+#define DEFAULT_NMI_WATCHDOG_VALUE NMI_AUTO
+#endif
unsigned int nmi_watchdog = DEFAULT_NMI_WATCHDOG_VALUE;
EXPORT_SYMBOL(nmi_watchdog);
@@ -196,6 +199,22 @@ error:
return -1;
}
+/* this function handles nmi_watchdog=NMI_AUTO */
+void __init default_nmi_watchdog(void)
+{
+ if (nmi_watchdog != NMI_AUTO)
+ return;
+
+ if (lapic_watchdog_detect() == 0)
+ nmi_watchdog = NMI_LOCAL_APIC;
+ else {
+ printk(KERN_INFO "NMI watchdog: LAPIC mode not available on this "
+ "CPU, using IOAPIC\n");
+ nmi_watchdog = NMI_IO_APIC;
+ }
+}
+
+
static int __init setup_nmi_watchdog(char *str)
{
unsigned int nmi;
@@ -212,6 +231,8 @@ static int __init setup_nmi_watchdog(char *str)
nmi_watchdog = NMI_LOCAL_APIC;
else if (!strncmp(str, "ioapic", 6))
nmi_watchdog = NMI_IO_APIC;
+ else if (!strncmp(str, "auto", 4))
+ nmi_watchdog = NMI_AUTO;
else {
get_option(&str, &nmi);
if (nmi >= NMI_INVALID)
diff --git a/arch/x86/kernel/cpu/perfctr-watchdog.c b/arch/x86/kernel/cpu/perfctr-watchdog.c
index e60ed74..bbd43b4 100644
--- a/arch/x86/kernel/cpu/perfctr-watchdog.c
+++ b/arch/x86/kernel/cpu/perfctr-watchdog.c
@@ -749,9 +749,7 @@ static void probe_nmi_watchdog(void)
}
}
-/* Interface to nmi.c */
-
-int lapic_watchdog_init(unsigned nmi_hz)
+int lapic_watchdog_detect(void)
{
if (!wd_ops) {
probe_nmi_watchdog();
@@ -766,6 +764,14 @@ int lapic_watchdog_init(unsigned nmi_hz)
return -1;
}
}
+ return 0;
+}
+
+/* Interface to nmi.c */
+int lapic_watchdog_init(unsigned nmi_hz)
+{
+ if (lapic_watchdog_detect())
+ return -1;
if (!(wd_ops->setup(nmi_hz))) {
printk(KERN_ERR "Cannot setup NMI watchdog on CPU %d\n",
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0a3622a..3898c19 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -261,6 +261,8 @@ choice
This allows to set the default NMI watchdog method to be used. The
default can be changed using nmi_watchdog=. Only choose an option
different from Disabled if you know the machine supports that method.
+ "Auto" option will first try detecting a LAPIC supported processor
+ then try IOAPIC if it fails.
config DEBUG_DEFAULT_NMI_NONE
bool "Disabled"
@@ -271,6 +273,9 @@ config DEBUG_DEFAULT_NMI_IOAPIC
config DEBUG_DEFAULT_NMI_LAPIC
bool "LAPIC"
+config DEBUG_DEFAULT_NMI_AUTO
+ bool "Auto"
+
endchoice
--
1.5.5.6
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists