* [PATCH] allow drivers to claim the lapic NMI watchdog HW
@ 2004-05-04 2:33 Mikael Pettersson
2004-05-04 11:02 ` John Levon
0 siblings, 1 reply; 5+ messages in thread
From: Mikael Pettersson @ 2004-05-04 2:33 UTC (permalink / raw)
To: linux-kernel, oprofile-list; +Cc: torvalds
This patch implements a simple ownership-tracking API
in the NMI watchdog on i386 and x86_64. Its purpose is
to allow other drivers (oprofile, perfctr, perhaps vtune)
to safely claim and use the performance counters and local
APIC LVTPC without conflicts. Of course, only one driver
can use the hardware at any given point in time.
The present situation is that no such API exists,
so these drivers directly access the hardware after
disabling the NMI watchdog. However, this is unsafe
if more than one driver needs the hardware.
This patch has been successfully tested in 2.6.6-rc3 with
the NMI watchdog, oprofile, and the perfctr drivers all
present: when oprofile is active, perfctr cannot claim
the hardware, and vice versa. Also, when the hardware is
released after having been reassigned to a different driver,
the NMI watchdog automatically restarts.
Please consider merging this in 2.6.
/Mikael
diff -ruN linux-2.6.6-rc3/arch/i386/kernel/nmi.c linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/kernel/nmi.c
--- linux-2.6.6-rc3/arch/i386/kernel/nmi.c 2004-05-03 20:43:29.000000000 +0200
+++ linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/kernel/nmi.c 2004-05-03 20:48:15.000000000 +0200
@@ -36,6 +36,20 @@
unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
extern void show_registers(struct pt_regs *regs);
+/* lapic_nmi_owner:
+ * +1: the lapic NMI hardware is assigned to the lapic NMI watchdog
+ * 0: the lapic NMI hardware is unassigned
+ * -1: the lapic NMI hardware is assigned to a different driver;
+ * on release it is reassigned to the lapic NMI watchdog
+ * -2: the lapic NMI hardware is assigned to a different driver;
+ * on release it is marked unassigned
+ *
+ * This is maintained separately from nmi_active because the NMI
+ * watchdog may also be driven from the I/O APIC timer.
+ */
+static spinlock_t lapic_nmi_owner_lock = SPIN_LOCK_UNLOCKED;
+static int lapic_nmi_owner;
+
/* nmi_active:
* +1: the lapic NMI watchdog is active, but can be disabled
* 0: the lapic NMI watchdog has not been set up, and cannot
@@ -102,6 +116,8 @@
if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
printk("CPU#%d: NMI appears to be stuck!\n", cpu);
nmi_active = 0;
+ if (lapic_nmi_owner > 0)
+ lapic_nmi_owner = 0;
return -1;
}
}
@@ -151,7 +167,7 @@
__setup("nmi_watchdog=", setup_nmi_watchdog);
-void disable_lapic_nmi_watchdog(void)
+static void disable_lapic_nmi_watchdog(void)
{
if (nmi_active <= 0)
return;
@@ -182,7 +198,7 @@
nmi_watchdog = 0;
}
-void enable_lapic_nmi_watchdog(void)
+static void enable_lapic_nmi_watchdog(void)
{
if (nmi_active < 0) {
nmi_watchdog = NMI_LOCAL_APIC;
@@ -190,6 +206,33 @@
}
}
+int reassign_lapic_nmi_watchdog(void)
+{
+ int old_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ old_owner = lapic_nmi_owner;
+ if (old_owner >= 0)
+ lapic_nmi_owner -= 2; /* +1 -> -1, 0 -> -2 */
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (old_owner < 0)
+ return -EBUSY;
+ if (old_owner > 0)
+ disable_lapic_nmi_watchdog();
+ return 0;
+}
+
+void release_lapic_nmi_watchdog(void)
+{
+ int new_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ lapic_nmi_owner = new_owner = lapic_nmi_owner + 2; /* -2 -> 0, -1 -> +1 */
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (new_owner > 0)
+ enable_lapic_nmi_watchdog();
+}
+
void disable_timer_nmi_watchdog(void)
{
if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
@@ -243,7 +286,7 @@
{
int error;
- if (nmi_active == 0)
+ if (nmi_active == 0 || nmi_watchdog != NMI_LOCAL_APIC)
return 0;
error = sysdev_class_register(&nmi_sysclass);
@@ -373,6 +416,7 @@
default:
return;
}
+ lapic_nmi_owner = 1;
nmi_active = 1;
}
@@ -470,7 +514,7 @@
EXPORT_SYMBOL(nmi_active);
EXPORT_SYMBOL(nmi_watchdog);
-EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
-EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
+EXPORT_SYMBOL(reassign_lapic_nmi_watchdog);
+EXPORT_SYMBOL(release_lapic_nmi_watchdog);
EXPORT_SYMBOL(disable_timer_nmi_watchdog);
EXPORT_SYMBOL(enable_timer_nmi_watchdog);
diff -ruN linux-2.6.6-rc3/arch/i386/oprofile/nmi_int.c linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/oprofile/nmi_int.c
--- linux-2.6.6-rc3/arch/i386/oprofile/nmi_int.c 2004-03-11 14:01:25.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/oprofile/nmi_int.c 2004-05-03 20:47:06.000000000 +0200
@@ -183,7 +183,10 @@
* without actually triggering any NMIs as this will
* break the core code horrifically.
*/
- disable_lapic_nmi_watchdog();
+ if (reassign_lapic_nmi_watchdog() < 0) {
+ free_msrs();
+ return -EBUSY;
+ }
/* We need to serialize save and setup for HT because the subset
* of msrs are distinct for save and setup operations
*/
@@ -241,7 +244,7 @@
nmi_enabled = 0;
on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
unset_nmi_callback();
- enable_lapic_nmi_watchdog();
+ release_lapic_nmi_watchdog();
free_msrs();
}
diff -ruN linux-2.6.6-rc3/arch/x86_64/kernel/nmi.c linux-2.6.6-rc3.lapic_nmi_owner/arch/x86_64/kernel/nmi.c
--- linux-2.6.6-rc3/arch/x86_64/kernel/nmi.c 2004-03-11 14:01:27.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/arch/x86_64/kernel/nmi.c 2004-05-03 20:49:54.000000000 +0200
@@ -33,6 +33,20 @@
#include <asm/proto.h>
#include <asm/kdebug.h>
+/* lapic_nmi_owner:
+ * +1: the lapic NMI hardware is assigned to the lapic NMI watchdog
+ * 0: the lapic NMI hardware is unassigned
+ * -1: the lapic NMI hardware is assigned to a different driver;
+ * on release it is reassigned to the lapic NMI watchdog
+ * -2: the lapic NMI hardware is assigned to a different driver;
+ * on release it is marked unassigned
+ *
+ * This is maintained separately from nmi_active because the NMI
+ * watchdog may also be driven from the I/O APIC timer.
+ */
+static spinlock_t lapic_nmi_owner_lock = SPIN_LOCK_UNLOCKED;
+static int lapic_nmi_owner;
+
/* nmi_active:
* +1: the lapic NMI watchdog is active, but can be disabled
* 0: the lapic NMI watchdog has not been set up, and cannot
@@ -122,6 +136,8 @@
cpu,
cpu_pda[cpu].__nmi_count);
nmi_active = 0;
+ if (lapic_nmi_owner > 0)
+ lapic_nmi_owner = 0;
return -1;
}
}
@@ -157,7 +173,7 @@
__setup("nmi_watchdog=", setup_nmi_watchdog);
-void disable_lapic_nmi_watchdog(void)
+static void disable_lapic_nmi_watchdog(void)
{
if (nmi_active <= 0)
return;
@@ -174,7 +190,7 @@
nmi_watchdog = 0;
}
-void enable_lapic_nmi_watchdog(void)
+static void enable_lapic_nmi_watchdog(void)
{
if (nmi_active < 0) {
nmi_watchdog = NMI_LOCAL_APIC;
@@ -182,6 +198,33 @@
}
}
+int reassign_lapic_nmi_watchdog(void)
+{
+ int old_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ old_owner = lapic_nmi_owner;
+ if (old_owner >= 0)
+ lapic_nmi_owner -= 2; /* +1 -> -1, 0 -> -2 */
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (old_owner < 0)
+ return -EBUSY;
+ if (old_owner > 0)
+ disable_lapic_nmi_watchdog();
+ return 0;
+}
+
+void release_lapic_nmi_watchdog(void)
+{
+ int new_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ lapic_nmi_owner = new_owner = lapic_nmi_owner + 2; /* -2 -> 0, -1 -> +1 */
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (new_owner > 0)
+ enable_lapic_nmi_watchdog();
+}
+
void disable_timer_nmi_watchdog(void)
{
if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
@@ -236,7 +279,7 @@
{
int error;
- if (nmi_active == 0)
+ if (nmi_active == 0 || nmi_watchdog != NMI_LOCAL_APIC)
return 0;
error = sysdev_class_register(&nmi_sysclass);
@@ -298,6 +341,7 @@
default:
return;
}
+ lapic_nmi_owner = 1;
nmi_active = 1;
}
@@ -405,8 +449,8 @@
EXPORT_SYMBOL(nmi_active);
EXPORT_SYMBOL(nmi_watchdog);
-EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
-EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
+EXPORT_SYMBOL(reassign_lapic_nmi_watchdog);
+EXPORT_SYMBOL(release_lapic_nmi_watchdog);
EXPORT_SYMBOL(disable_timer_nmi_watchdog);
EXPORT_SYMBOL(enable_timer_nmi_watchdog);
EXPORT_SYMBOL(touch_nmi_watchdog);
diff -ruN linux-2.6.6-rc3/include/asm-i386/apic.h linux-2.6.6-rc3.lapic_nmi_owner/include/asm-i386/apic.h
--- linux-2.6.6-rc3/include/asm-i386/apic.h 2004-02-18 11:09:53.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/include/asm-i386/apic.h 2004-05-03 20:45:58.000000000 +0200
@@ -81,8 +81,8 @@
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern void setup_apic_nmi_watchdog (void);
-extern void disable_lapic_nmi_watchdog(void);
-extern void enable_lapic_nmi_watchdog(void);
+extern int reassign_lapic_nmi_watchdog(void);
+extern void release_lapic_nmi_watchdog(void);
extern void disable_timer_nmi_watchdog(void);
extern void enable_timer_nmi_watchdog(void);
extern void nmi_watchdog_tick (struct pt_regs * regs);
diff -ruN linux-2.6.6-rc3/include/asm-x86_64/apic.h linux-2.6.6-rc3.lapic_nmi_owner/include/asm-x86_64/apic.h
--- linux-2.6.6-rc3/include/asm-x86_64/apic.h 2004-03-11 14:01:30.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/include/asm-x86_64/apic.h 2004-05-03 20:46:36.000000000 +0200
@@ -75,8 +75,8 @@
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern void setup_apic_nmi_watchdog (void);
-extern void disable_lapic_nmi_watchdog(void);
-extern void enable_lapic_nmi_watchdog(void);
+extern int reassign_lapic_nmi_watchdog(void);
+extern void release_lapic_nmi_watchdog(void);
extern void disable_timer_nmi_watchdog(void);
extern void enable_timer_nmi_watchdog(void);
extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] allow drivers to claim the lapic NMI watchdog HW
2004-05-04 2:33 [PATCH] allow drivers to claim the lapic NMI watchdog HW Mikael Pettersson
@ 2004-05-04 11:02 ` John Levon
2004-05-04 15:57 ` Mikael Pettersson
0 siblings, 1 reply; 5+ messages in thread
From: John Levon @ 2004-05-04 11:02 UTC (permalink / raw)
To: Mikael Pettersson; +Cc: linux-kernel, oprofile-list, torvalds
On Tue, May 04, 2004 at 04:33:01AM +0200, Mikael Pettersson wrote:
> +/* lapic_nmi_owner:
> + * +1: the lapic NMI hardware is assigned to the lapic NMI watchdog
> + * 0: the lapic NMI hardware is unassigned
If we're going to have a mini state machine, can't we at least use some
defines for each state...
> + lapic_nmi_owner -= 2; /* +1 -> -1, 0 -> -2 */
...and make this into some readable english via a little helper?
> -EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
> -EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
> +EXPORT_SYMBOL(reassign_lapic_nmi_watchdog);
> +EXPORT_SYMBOL(release_lapic_nmi_watchdog);
I don't like this new naming. Since the patch is really all about
ownership of the local APIC, can't we call it something like
acquire_lapic_nmi()
release_lapic_nmi()
Neither perfctr nor oprofile have anything to do with watchdogs, so
this:
> - disable_lapic_nmi_watchdog();
> + if (reassign_lapic_nmi_watchdog() < 0) {
Looks a little weird now.
regards
john
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] allow drivers to claim the lapic NMI watchdog HW
2004-05-04 11:02 ` John Levon
@ 2004-05-04 15:57 ` Mikael Pettersson
2004-05-04 13:49 ` Albert Cahalan
0 siblings, 1 reply; 5+ messages in thread
From: Mikael Pettersson @ 2004-05-04 15:57 UTC (permalink / raw)
To: John Levon; +Cc: linux-kernel, oprofile-list, torvalds
John Levon writes:
> On Tue, May 04, 2004 at 04:33:01AM +0200, Mikael Pettersson wrote:
>
> > +/* lapic_nmi_owner:
> > + * +1: the lapic NMI hardware is assigned to the lapic NMI watchdog
> > + * 0: the lapic NMI hardware is unassigned
>
> If we're going to have a mini state machine, can't we at least use some
> defines for each state...
>
> > + lapic_nmi_owner -= 2; /* +1 -> -1, 0 -> -2 */
>
> ...and make this into some readable english via a little helper?
Thing is, using discrete states makes the code for the checks
and state changes more verbose. However, I can easily hide the
representation behind macros with understandable names.
> > -EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
> > -EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
> > +EXPORT_SYMBOL(reassign_lapic_nmi_watchdog);
> > +EXPORT_SYMBOL(release_lapic_nmi_watchdog);
>
> I don't like this new naming. Since the patch is really all about
> ownership of the local APIC, can't we call it something like
>
> acquire_lapic_nmi()
> release_lapic_nmi()
Yep, those are nicer names.
> Neither perfctr nor oprofile have anything to do with watchdogs, so
> this:
>
> > - disable_lapic_nmi_watchdog();
> > + if (reassign_lapic_nmi_watchdog() < 0) {
>
> Looks a little weird now.
A little, yes.
I'll implement these changes this evening and post an updated patch tomorrow.
/Mikael
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] allow drivers to claim the lapic NMI watchdog HW
2004-05-04 15:57 ` Mikael Pettersson
@ 2004-05-04 13:49 ` Albert Cahalan
2004-05-05 9:19 ` [PATCH][updated] " Mikael Pettersson
0 siblings, 1 reply; 5+ messages in thread
From: Albert Cahalan @ 2004-05-04 13:49 UTC (permalink / raw)
To: Mikael Pettersson
Cc: John Levon, linux-kernel mailing list, oprofile-list,
Linus Torvalds
On Tue, 2004-05-04 at 11:57, Mikael Pettersson wrote:
> John Levon writes:
> > On Tue, May 04, 2004 at 04:33:01AM +0200, Mikael Pettersson wrote:
> >
> > > +/* lapic_nmi_owner:
> > > + * +1: the lapic NMI hardware is assigned to the lapic NMI watchdog
> > > + * 0: the lapic NMI hardware is unassigned
> >
> > If we're going to have a mini state machine, can't we at least use some
> > defines for each state...
> >
> > > + lapic_nmi_owner -= 2; /* +1 -> -1, 0 -> -2 */
> >
> > ...and make this into some readable english via a little helper?
>
> Thing is, using discrete states makes the code for the checks
> and state changes more verbose. However, I can easily hide the
> representation behind macros with understandable names.
It looked like 2 flag bits to me.
#define LAPIC_WATCHDOG_WANTS_NMI 0x00000001
#define LAPIC_OTHER_DRIVER_HAS_NMI 0x00000002
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH][updated] allow drivers to claim the lapic NMI watchdog HW
2004-05-04 13:49 ` Albert Cahalan
@ 2004-05-05 9:19 ` Mikael Pettersson
0 siblings, 0 replies; 5+ messages in thread
From: Mikael Pettersson @ 2004-05-05 9:19 UTC (permalink / raw)
To: linux-kernel mailing list, oprofile-list
Cc: Albert Cahalan, John Levon, Linus Torvalds
Here is an updated lapic NMI ownership tracking patch which
should address the issues that were raised with the first one:
- Simplified the API function names to {reserve,release}_lapic_nmi().
- Rewrote the ownership tracking code to use two individually named
flags instead of using arithmetic and the sign. The code is now
simple enough that no "hiding" macros are needed. (Thanks Albert
for that suggestion.)
/Mikael
diff -ruN linux-2.6.6-rc3/arch/i386/kernel/nmi.c linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/kernel/nmi.c
--- linux-2.6.6-rc3/arch/i386/kernel/nmi.c 2004-05-04 23:21:26.000000000 +0200
+++ linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/kernel/nmi.c 2004-05-05 00:39:59.000000000 +0200
@@ -36,6 +36,20 @@
unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
extern void show_registers(struct pt_regs *regs);
+/*
+ * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
+ * - it may be reserved by some other driver, or not
+ * - when not reserved by some other driver, it may be used for
+ * the NMI watchdog, or not
+ *
+ * This is maintained separately from nmi_active because the NMI
+ * watchdog may also be driven from the I/O APIC timer.
+ */
+static spinlock_t lapic_nmi_owner_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int lapic_nmi_owner;
+#define LAPIC_NMI_WATCHDOG (1<<0)
+#define LAPIC_NMI_RESERVED (1<<1)
+
/* nmi_active:
* +1: the lapic NMI watchdog is active, but can be disabled
* 0: the lapic NMI watchdog has not been set up, and cannot
@@ -102,6 +116,7 @@
if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
printk("CPU#%d: NMI appears to be stuck!\n", cpu);
nmi_active = 0;
+ lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG;
return -1;
}
}
@@ -151,7 +166,7 @@
__setup("nmi_watchdog=", setup_nmi_watchdog);
-void disable_lapic_nmi_watchdog(void)
+static void disable_lapic_nmi_watchdog(void)
{
if (nmi_active <= 0)
return;
@@ -182,7 +197,7 @@
nmi_watchdog = 0;
}
-void enable_lapic_nmi_watchdog(void)
+static void enable_lapic_nmi_watchdog(void)
{
if (nmi_active < 0) {
nmi_watchdog = NMI_LOCAL_APIC;
@@ -190,6 +205,33 @@
}
}
+int reserve_lapic_nmi(void)
+{
+ unsigned int old_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ old_owner = lapic_nmi_owner;
+ lapic_nmi_owner |= LAPIC_NMI_RESERVED;
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (old_owner & LAPIC_NMI_RESERVED)
+ return -EBUSY;
+ if (old_owner & LAPIC_NMI_WATCHDOG)
+ disable_lapic_nmi_watchdog();
+ return 0;
+}
+
+void release_lapic_nmi(void)
+{
+ unsigned int new_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
+ lapic_nmi_owner = new_owner;
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (new_owner & LAPIC_NMI_WATCHDOG)
+ enable_lapic_nmi_watchdog();
+}
+
void disable_timer_nmi_watchdog(void)
{
if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
@@ -243,7 +285,7 @@
{
int error;
- if (nmi_active == 0)
+ if (nmi_active == 0 || nmi_watchdog != NMI_LOCAL_APIC)
return 0;
error = sysdev_class_register(&nmi_sysclass);
@@ -373,6 +415,7 @@
default:
return;
}
+ lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
nmi_active = 1;
}
@@ -470,7 +513,7 @@
EXPORT_SYMBOL(nmi_active);
EXPORT_SYMBOL(nmi_watchdog);
-EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
-EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
+EXPORT_SYMBOL(reserve_lapic_nmi);
+EXPORT_SYMBOL(release_lapic_nmi);
EXPORT_SYMBOL(disable_timer_nmi_watchdog);
EXPORT_SYMBOL(enable_timer_nmi_watchdog);
diff -ruN linux-2.6.6-rc3/arch/i386/oprofile/nmi_int.c linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/oprofile/nmi_int.c
--- linux-2.6.6-rc3/arch/i386/oprofile/nmi_int.c 2004-03-11 14:01:25.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/arch/i386/oprofile/nmi_int.c 2004-05-04 23:41:46.000000000 +0200
@@ -183,7 +183,10 @@
* without actually triggering any NMIs as this will
* break the core code horrifically.
*/
- disable_lapic_nmi_watchdog();
+ if (reserve_lapic_nmi() < 0) {
+ free_msrs();
+ return -EBUSY;
+ }
/* We need to serialize save and setup for HT because the subset
* of msrs are distinct for save and setup operations
*/
@@ -241,7 +244,7 @@
nmi_enabled = 0;
on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
unset_nmi_callback();
- enable_lapic_nmi_watchdog();
+ release_lapic_nmi();
free_msrs();
}
diff -ruN linux-2.6.6-rc3/arch/x86_64/kernel/nmi.c linux-2.6.6-rc3.lapic_nmi_owner/arch/x86_64/kernel/nmi.c
--- linux-2.6.6-rc3/arch/x86_64/kernel/nmi.c 2004-03-11 14:01:27.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/arch/x86_64/kernel/nmi.c 2004-05-05 00:46:41.000000000 +0200
@@ -33,6 +33,20 @@
#include <asm/proto.h>
#include <asm/kdebug.h>
+/*
+ * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
+ * - it may be reserved by some other driver, or not
+ * - when not reserved by some other driver, it may be used for
+ * the NMI watchdog, or not
+ *
+ * This is maintained separately from nmi_active because the NMI
+ * watchdog may also be driven from the I/O APIC timer.
+ */
+static spinlock_t lapic_nmi_owner_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int lapic_nmi_owner;
+#define LAPIC_NMI_WATCHDOG (1<<0)
+#define LAPIC_NMI_RESERVED (1<<1)
+
/* nmi_active:
* +1: the lapic NMI watchdog is active, but can be disabled
* 0: the lapic NMI watchdog has not been set up, and cannot
@@ -122,6 +136,7 @@
cpu,
cpu_pda[cpu].__nmi_count);
nmi_active = 0;
+ lapic_nmi_owner &= ~LAPIC_NMI_WATCHDOG;
return -1;
}
}
@@ -157,7 +172,7 @@
__setup("nmi_watchdog=", setup_nmi_watchdog);
-void disable_lapic_nmi_watchdog(void)
+static void disable_lapic_nmi_watchdog(void)
{
if (nmi_active <= 0)
return;
@@ -174,7 +189,7 @@
nmi_watchdog = 0;
}
-void enable_lapic_nmi_watchdog(void)
+static void enable_lapic_nmi_watchdog(void)
{
if (nmi_active < 0) {
nmi_watchdog = NMI_LOCAL_APIC;
@@ -182,6 +197,33 @@
}
}
+int reserve_lapic_nmi(void)
+{
+ unsigned int old_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ old_owner = lapic_nmi_owner;
+ lapic_nmi_owner |= LAPIC_NMI_RESERVED;
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (old_owner & LAPIC_NMI_RESERVED)
+ return -EBUSY;
+ if (old_owner & LAPIC_NMI_WATCHDOG)
+ disable_lapic_nmi_watchdog();
+ return 0;
+}
+
+void release_lapic_nmi(void)
+{
+ unsigned int new_owner;
+
+ spin_lock(&lapic_nmi_owner_lock);
+ new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
+ lapic_nmi_owner = new_owner;
+ spin_unlock(&lapic_nmi_owner_lock);
+ if (new_owner & LAPIC_NMI_WATCHDOG)
+ enable_lapic_nmi_watchdog();
+}
+
void disable_timer_nmi_watchdog(void)
{
if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
@@ -236,7 +278,7 @@
{
int error;
- if (nmi_active == 0)
+ if (nmi_active == 0 || nmi_watchdog != NMI_LOCAL_APIC)
return 0;
error = sysdev_class_register(&nmi_sysclass);
@@ -298,6 +340,7 @@
default:
return;
}
+ lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
nmi_active = 1;
}
@@ -405,8 +448,8 @@
EXPORT_SYMBOL(nmi_active);
EXPORT_SYMBOL(nmi_watchdog);
-EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
-EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
+EXPORT_SYMBOL(reserve_lapic_nmi);
+EXPORT_SYMBOL(release_lapic_nmi);
EXPORT_SYMBOL(disable_timer_nmi_watchdog);
EXPORT_SYMBOL(enable_timer_nmi_watchdog);
EXPORT_SYMBOL(touch_nmi_watchdog);
diff -ruN linux-2.6.6-rc3/include/asm-i386/apic.h linux-2.6.6-rc3.lapic_nmi_owner/include/asm-i386/apic.h
--- linux-2.6.6-rc3/include/asm-i386/apic.h 2004-02-18 11:09:53.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/include/asm-i386/apic.h 2004-05-04 23:40:57.000000000 +0200
@@ -81,8 +81,8 @@
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern void setup_apic_nmi_watchdog (void);
-extern void disable_lapic_nmi_watchdog(void);
-extern void enable_lapic_nmi_watchdog(void);
+extern int reserve_lapic_nmi(void);
+extern void release_lapic_nmi(void);
extern void disable_timer_nmi_watchdog(void);
extern void enable_timer_nmi_watchdog(void);
extern void nmi_watchdog_tick (struct pt_regs * regs);
diff -ruN linux-2.6.6-rc3/include/asm-x86_64/apic.h linux-2.6.6-rc3.lapic_nmi_owner/include/asm-x86_64/apic.h
--- linux-2.6.6-rc3/include/asm-x86_64/apic.h 2004-03-11 14:01:30.000000000 +0100
+++ linux-2.6.6-rc3.lapic_nmi_owner/include/asm-x86_64/apic.h 2004-05-04 23:41:22.000000000 +0200
@@ -75,8 +75,8 @@
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern void setup_apic_nmi_watchdog (void);
-extern void disable_lapic_nmi_watchdog(void);
-extern void enable_lapic_nmi_watchdog(void);
+extern int reserve_lapic_nmi(void);
+extern void release_lapic_nmi(void);
extern void disable_timer_nmi_watchdog(void);
extern void enable_timer_nmi_watchdog(void);
extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2004-05-05 9:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-04 2:33 [PATCH] allow drivers to claim the lapic NMI watchdog HW Mikael Pettersson
2004-05-04 11:02 ` John Levon
2004-05-04 15:57 ` Mikael Pettersson
2004-05-04 13:49 ` Albert Cahalan
2004-05-05 9:19 ` [PATCH][updated] " Mikael Pettersson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox