diff --git a/[refs] b/[refs]
index 57361d63bc9b..c387ebb7a4f9 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: 4c635a4e04700a371ef7e4d4bb33ed88747e801e
+refs/heads/master: 133dc4c39c57eeef2577ca5b4ed24765b7a78ce2
diff --git a/trunk/CREDITS b/trunk/CREDITS
index 494b6e4746d7..41d8e63d5165 100644
--- a/trunk/CREDITS
+++ b/trunk/CREDITS
@@ -2365,6 +2365,8 @@ E: acme@redhat.com
W: http://oops.ghostprotocols.net:81/blog/
P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD 841A B6AB 4681 9224 DF01
D: IPX, LLC, DCCP, cyc2x, wl3501_cs, net/ hacks
+S: R. Brasílio Itiberê, 4270/1010 - Água Verde
+S: 80240-060 - Curitiba - Paraná
S: Brazil
N: Karsten Merker
diff --git a/trunk/Documentation/DocBook/uio-howto.tmpl b/trunk/Documentation/DocBook/uio-howto.tmpl
index b4665b9c40b0..4d4ce0e61e42 100644
--- a/trunk/Documentation/DocBook/uio-howto.tmpl
+++ b/trunk/Documentation/DocBook/uio-howto.tmpl
@@ -16,7 +16,7 @@
- hjk@hansjkoch.de
+ hjk@linutronix.de
@@ -114,7 +114,7 @@ GPL version 2.
If you know of any translations for this document, or you are
interested in translating it, please email me
-hjk@hansjkoch.de.
+hjk@linutronix.de.
@@ -171,7 +171,7 @@ interested in translating it, please email me
Feedback
Find something wrong with this document? (Or perhaps something
right?) I would love to hear from you. Please email me at
- hjk@hansjkoch.de.
+ hjk@linutronix.de.
diff --git a/trunk/Documentation/development-process/2.Process b/trunk/Documentation/development-process/2.Process
index 911a45186340..97726eba6102 100644
--- a/trunk/Documentation/development-process/2.Process
+++ b/trunk/Documentation/development-process/2.Process
@@ -154,7 +154,7 @@ The stages that a patch goes through are, generally:
inclusion, it should be accepted by a relevant subsystem maintainer -
though this acceptance is not a guarantee that the patch will make it
all the way to the mainline. The patch will show up in the maintainer's
- subsystem tree and into the -next trees (described below). When the
+ subsystem tree and into the staging trees (described below). When the
process works, this step leads to more extensive review of the patch and
the discovery of any problems resulting from the integration of this
patch with work being done by others.
@@ -236,7 +236,7 @@ finding the right maintainer. Sending patches directly to Linus is not
normally the right way to go.
-2.4: NEXT TREES
+2.4: STAGING TREES
The chain of subsystem trees guides the flow of patches into the kernel,
but it also raises an interesting question: what if somebody wants to look
@@ -250,7 +250,7 @@ changes land in the mainline kernel. One could pull changes from all of
the interesting subsystem trees, but that would be a big and error-prone
job.
-The answer comes in the form of -next trees, where subsystem trees are
+The answer comes in the form of staging trees, where subsystem trees are
collected for testing and review. The older of these trees, maintained by
Andrew Morton, is called "-mm" (for memory management, which is how it got
started). The -mm tree integrates patches from a long list of subsystem
@@ -275,7 +275,7 @@ directory at:
Use of the MMOTM tree is likely to be a frustrating experience, though;
there is a definite chance that it will not even compile.
-The other -next tree, started more recently, is linux-next, maintained by
+The other staging tree, started more recently, is linux-next, maintained by
Stephen Rothwell. The linux-next tree is, by design, a snapshot of what
the mainline is expected to look like after the next merge window closes.
Linux-next trees are announced on the linux-kernel and linux-next mailing
@@ -303,25 +303,12 @@ volatility of linux-next tends to make it a difficult development target.
See http://lwn.net/Articles/289013/ for more information on this topic, and
stay tuned; much is still in flux where linux-next is involved.
-2.4.1: STAGING TREES
-
-The kernel source tree now contains the drivers/staging/ directory, where
-many sub-directories for drivers or filesystems that are on their way to
-being added to the kernel tree live. They remain in drivers/staging while
-they still need more work; once complete, they can be moved into the
-kernel proper. This is a way to keep track of drivers that aren't
-up to Linux kernel coding or quality standards, but people may want to use
-them and track development.
-
-Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree.
-Drivers that still need work are sent to him, with each driver having
-its own subdirectory in drivers/staging/. Along with the driver source
-files, a TODO file should be present in the directory as well. The TODO
-file lists the pending work that the driver needs for acceptance into
-the kernel proper, as well as a list of people that should be Cc'd for any
-patches to the driver. Staging drivers that don't currently build should
-have their config entries depend upon CONFIG_BROKEN. Once they can
-be successfully built without outside patches, CONFIG_BROKEN can be removed.
+Besides the mmotm and linux-next trees, the kernel source tree now contains
+the drivers/staging/ directory and many sub-directories for drivers or
+filesystems that are on their way to being added to the kernel tree
+proper, but they remain in drivers/staging/ while they still need more
+work.
+
2.5: TOOLS
diff --git a/trunk/Documentation/filesystems/configfs/configfs_example_explicit.c b/trunk/Documentation/filesystems/configfs/configfs_example_explicit.c
index fd53869f5633..d428cc9f07f3 100644
--- a/trunk/Documentation/filesystems/configfs/configfs_example_explicit.c
+++ b/trunk/Documentation/filesystems/configfs/configfs_example_explicit.c
@@ -89,7 +89,7 @@ static ssize_t childless_storeme_write(struct childless *childless,
char *p = (char *) page;
tmp = simple_strtoul(p, &p, 10);
- if ((*p != '\0') && (*p != '\n'))
+ if (!p || (*p && (*p != '\n')))
return -EINVAL;
if (tmp > INT_MAX)
diff --git a/trunk/Documentation/gpio.txt b/trunk/Documentation/gpio.txt
index 792faa3c06cf..9633da01ff46 100644
--- a/trunk/Documentation/gpio.txt
+++ b/trunk/Documentation/gpio.txt
@@ -617,16 +617,6 @@ and have the following read/write attributes:
is configured as an output, this value may be written;
any nonzero value is treated as high.
- If the pin can be configured as interrupt-generating interrupt
- and if it has been configured to generate interrupts (see the
- description of "edge"), you can poll(2) on that file and
- poll(2) will return whenever the interrupt was triggered. If
- you use poll(2), set the events POLLPRI and POLLERR. If you
- use select(2), set the file descriptor in exceptfds. After
- poll(2) returns, either lseek(2) to the beginning of the sysfs
- file and read the new value or close the file and re-open it
- to read the value.
-
"edge" ... reads as either "none", "rising", "falling", or
"both". Write these strings to select the signal edge(s)
that will make poll(2) on the "value" file return.
diff --git a/trunk/Documentation/hwmon/lm93 b/trunk/Documentation/hwmon/lm93
index 7a10616d0b44..ac711f357faf 100644
--- a/trunk/Documentation/hwmon/lm93
+++ b/trunk/Documentation/hwmon/lm93
@@ -11,7 +11,7 @@ Authors:
Mark M. Hoffman
Ported to 2.6 by Eric J. Bowersox
Adapted to 2.6.20 by Carsten Emde
- Modified for mainline integration by Hans J. Koch
+ Modified for mainline integration by Hans J. Koch
Module Parameters
-----------------
diff --git a/trunk/Documentation/hwmon/max6650 b/trunk/Documentation/hwmon/max6650
index c565650fcfc6..8be7beb9e3e8 100644
--- a/trunk/Documentation/hwmon/max6650
+++ b/trunk/Documentation/hwmon/max6650
@@ -8,7 +8,7 @@ Supported chips:
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
Authors:
- Hans J. Koch
+ Hans J. Koch
John Morris
Claus Gindhart
diff --git a/trunk/Documentation/power/opp.txt b/trunk/Documentation/power/opp.txt
index cd445582d1f8..44d87ad3cea9 100644
--- a/trunk/Documentation/power/opp.txt
+++ b/trunk/Documentation/power/opp.txt
@@ -37,9 +37,6 @@ Typical usage of the OPP library is as follows:
SoC framework -> modifies on required cases certain OPPs -> OPP layer
-> queries to search/retrieve information ->
-Architectures that provide a SoC framework for OPP should select ARCH_HAS_OPP
-to make the OPP layer available.
-
OPP layer expects each domain to be represented by a unique device pointer. SoC
framework registers a set of initial OPPs per device with the OPP layer. This
list is expected to be an optimally small number typically around 5 per device.
diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS
index 96e1a833e443..8e6548dbd5db 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -1829,13 +1829,6 @@ W: http://www.chelsio.com
S: Supported
F: drivers/net/cxgb4vf/
-STMMAC ETHERNET DRIVER
-M: Giuseppe Cavallaro
-L: netdev@vger.kernel.org
-W: http://www.stlinux.com
-S: Supported
-F: drivers/net/stmmac/
-
CYBERPRO FB DRIVER
M: Russell King
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2015,7 +2008,6 @@ F: drivers/hwmon/dme1737.c
DOCBOOK FOR DOCUMENTATION
M: Randy Dunlap
S: Maintained
-F: scripts/kernel-doc
DOCKING STATION DRIVER
M: Shaohua Li
@@ -2026,7 +2018,6 @@ F: drivers/acpi/dock.c
DOCUMENTATION
M: Randy Dunlap
L: linux-doc@vger.kernel.org
-T: quilt oss.oracle.com/~rdunlap/kernel-doc-patches/current/
S: Maintained
F: Documentation/
@@ -4611,7 +4602,7 @@ PERFORMANCE EVENTS SUBSYSTEM
M: Peter Zijlstra
M: Paul Mackerras
M: Ingo Molnar
-M: Arnaldo Carvalho de Melo
+M: Arnaldo Carvalho de Melo
S: Supported
F: kernel/perf_event*.c
F: include/linux/perf_event.h
diff --git a/trunk/Makefile b/trunk/Makefile
index b31d21377e4c..ab5359db3d17 100644
--- a/trunk/Makefile
+++ b/trunk/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 37
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc2
NAME = Flesh-Eating Bats with Fangs
# *DOCUMENTATION*
diff --git a/trunk/arch/alpha/include/asm/perf_event.h b/trunk/arch/alpha/include/asm/perf_event.h
index 5996e7a6757e..fe792ca818f6 100644
--- a/trunk/arch/alpha/include/asm/perf_event.h
+++ b/trunk/arch/alpha/include/asm/perf_event.h
@@ -1,4 +1,10 @@
#ifndef __ASM_ALPHA_PERF_EVENT_H
#define __ASM_ALPHA_PERF_EVENT_H
+#ifdef CONFIG_PERF_EVENTS
+extern void init_hw_perf_events(void);
+#else
+static inline void init_hw_perf_events(void) { }
+#endif
+
#endif /* __ASM_ALPHA_PERF_EVENT_H */
diff --git a/trunk/arch/alpha/kernel/irq_alpha.c b/trunk/arch/alpha/kernel/irq_alpha.c
index 4c8bb374eb0a..5f77afb88e89 100644
--- a/trunk/arch/alpha/kernel/irq_alpha.c
+++ b/trunk/arch/alpha/kernel/irq_alpha.c
@@ -112,6 +112,8 @@ init_IRQ(void)
wrent(entInt, 0);
alpha_mv.init_irq();
+
+ init_hw_perf_events();
}
/*
diff --git a/trunk/arch/alpha/kernel/perf_event.c b/trunk/arch/alpha/kernel/perf_event.c
index 3283059b6e85..1cc49683fb69 100644
--- a/trunk/arch/alpha/kernel/perf_event.c
+++ b/trunk/arch/alpha/kernel/perf_event.c
@@ -14,7 +14,6 @@
#include
#include
#include
-#include
#include
#include
@@ -864,13 +863,13 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr,
/*
* Init call to initialise performance events at kernel startup.
*/
-int __init init_hw_perf_events(void)
+void __init init_hw_perf_events(void)
{
pr_info("Performance events: ");
if (!supported_cpu()) {
pr_cont("No support for your CPU.\n");
- return 0;
+ return;
}
pr_cont("Supported CPU type!\n");
@@ -883,7 +882,5 @@ int __init init_hw_perf_events(void)
alpha_pmu = &ev67_pmu;
perf_pmu_register(&pmu);
-
- return 0;
}
-early_initcall(init_hw_perf_events);
+
diff --git a/trunk/arch/arm/kernel/perf_event.c b/trunk/arch/arm/kernel/perf_event.c
index d45f70e5f2ee..07a50357492a 100644
--- a/trunk/arch/arm/kernel/perf_event.c
+++ b/trunk/arch/arm/kernel/perf_event.c
@@ -3038,7 +3038,7 @@ init_hw_perf_events(void)
return 0;
}
-early_initcall(init_hw_perf_events);
+arch_initcall(init_hw_perf_events);
/*
* Callchain handling code.
diff --git a/trunk/arch/blackfin/kernel/process.c b/trunk/arch/blackfin/kernel/process.c
index b407bc8ad918..cd0c090ebc54 100644
--- a/trunk/arch/blackfin/kernel/process.c
+++ b/trunk/arch/blackfin/kernel/process.c
@@ -7,6 +7,7 @@
*/
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/frv/kernel/process.c b/trunk/arch/frv/kernel/process.c
index efad12071c2e..2b63b0191f52 100644
--- a/trunk/arch/frv/kernel/process.c
+++ b/trunk/arch/frv/kernel/process.c
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/h8300/kernel/process.c b/trunk/arch/h8300/kernel/process.c
index 933bd388efb2..97478138e361 100644
--- a/trunk/arch/h8300/kernel/process.c
+++ b/trunk/arch/h8300/kernel/process.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/ia64/hp/sim/simscsi.c b/trunk/arch/ia64/hp/sim/simscsi.c
index 331de723c676..3a078ad3aa44 100644
--- a/trunk/arch/ia64/hp/sim/simscsi.c
+++ b/trunk/arch/ia64/hp/sim/simscsi.c
@@ -202,7 +202,7 @@ simscsi_readwrite10 (struct scsi_cmnd *sc, int mode)
}
static int
-simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
{
unsigned int target_id = sc->device->id;
char fname[MAX_ROOT_LEN+16];
@@ -326,8 +326,6 @@ simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)
return 0;
}
-static DEF_SCSI_QCMD(simscsi_queuecommand)
-
static int
simscsi_host_reset (struct scsi_cmnd *sc)
{
diff --git a/trunk/arch/m68k/kernel/process.c b/trunk/arch/m68k/kernel/process.c
index c2a1fc23dd75..18732ab23292 100644
--- a/trunk/arch/m68k/kernel/process.c
+++ b/trunk/arch/m68k/kernel/process.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/m68knommu/kernel/process.c b/trunk/arch/m68knommu/kernel/process.c
index e2a63af5d517..6d3390590e5b 100644
--- a/trunk/arch/m68knommu/kernel/process.c
+++ b/trunk/arch/m68knommu/kernel/process.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/mips/kernel/perf_event_mipsxx.c b/trunk/arch/mips/kernel/perf_event_mipsxx.c
index 183e0d226669..5c7c6fc07565 100644
--- a/trunk/arch/mips/kernel/perf_event_mipsxx.c
+++ b/trunk/arch/mips/kernel/perf_event_mipsxx.c
@@ -1047,6 +1047,6 @@ init_hw_perf_events(void)
return 0;
}
-early_initcall(init_hw_perf_events);
+arch_initcall(init_hw_perf_events);
#endif /* defined(CONFIG_CPU_MIPS32)... */
diff --git a/trunk/arch/mn10300/kernel/process.c b/trunk/arch/mn10300/kernel/process.c
index e1b14a6ed544..0d0f8049a17b 100644
--- a/trunk/arch/mn10300/kernel/process.c
+++ b/trunk/arch/mn10300/kernel/process.c
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/parisc/hpux/sys_hpux.c b/trunk/arch/parisc/hpux/sys_hpux.c
index 30394081d9b6..ba430a03bc7a 100644
--- a/trunk/arch/parisc/hpux/sys_hpux.c
+++ b/trunk/arch/parisc/hpux/sys_hpux.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/parisc/kernel/sys_parisc32.c b/trunk/arch/parisc/kernel/sys_parisc32.c
index 88a0ad14a9c9..9779ece2b070 100644
--- a/trunk/arch/parisc/kernel/sys_parisc32.c
+++ b/trunk/arch/parisc/kernel/sys_parisc32.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig
index e625e9e034ae..b6447190e1a2 100644
--- a/trunk/arch/powerpc/Kconfig
+++ b/trunk/arch/powerpc/Kconfig
@@ -4,10 +4,6 @@ config PPC32
bool
default y if !PPC64
-config 32BIT
- bool
- default y if PPC32
-
config 64BIT
bool
default y if PPC64
diff --git a/trunk/arch/powerpc/boot/div64.S b/trunk/arch/powerpc/boot/div64.S
index d271ab542673..722f360a32a9 100644
--- a/trunk/arch/powerpc/boot/div64.S
+++ b/trunk/arch/powerpc/boot/div64.S
@@ -33,10 +33,9 @@ __div64_32:
cntlzw r0,r5 # we are shifting the dividend right
li r10,-1 # to make it < 2^32, and shifting
srw r10,r10,r0 # the divisor right the same amount,
- addc r9,r4,r10 # rounding up (so the estimate cannot
+ add r9,r4,r10 # rounding up (so the estimate cannot
andc r11,r6,r10 # ever be too large, only too small)
andc r9,r9,r10
- addze r9,r9
or r11,r5,r11
rotlw r9,r9,r0
rotlw r11,r11,r0
diff --git a/trunk/arch/powerpc/kernel/e500-pmu.c b/trunk/arch/powerpc/kernel/e500-pmu.c
index b150b510510f..7c07de0d8943 100644
--- a/trunk/arch/powerpc/kernel/e500-pmu.c
+++ b/trunk/arch/powerpc/kernel/e500-pmu.c
@@ -126,4 +126,4 @@ static int init_e500_pmu(void)
return register_fsl_emb_pmu(&e500_pmu);
}
-early_initcall(init_e500_pmu);
+arch_initcall(init_e500_pmu);
diff --git a/trunk/arch/powerpc/kernel/kgdb.c b/trunk/arch/powerpc/kernel/kgdb.c
index 42850ee00ada..7a9db64f3f04 100644
--- a/trunk/arch/powerpc/kernel/kgdb.c
+++ b/trunk/arch/powerpc/kernel/kgdb.c
@@ -337,7 +337,7 @@ char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
if (current)
- memcpy(mem, ¤t->thread.evr[regno-32],
+ memcpy(mem, current->thread.evr[regno-32],
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
@@ -362,7 +362,7 @@ int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
if (regno >= 32 && regno < 64) {
/* FP registers 32 -> 63 */
#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
- memcpy(¤t->thread.evr[regno-32], mem,
+ memcpy(current->thread.evr[regno-32], mem,
dbg_reg_def[regno].size);
#else
/* fp registers not used by kernel, leave zero */
diff --git a/trunk/arch/powerpc/kernel/mpc7450-pmu.c b/trunk/arch/powerpc/kernel/mpc7450-pmu.c
index 2cc5e0301d0b..09d72028f317 100644
--- a/trunk/arch/powerpc/kernel/mpc7450-pmu.c
+++ b/trunk/arch/powerpc/kernel/mpc7450-pmu.c
@@ -414,4 +414,4 @@ static int init_mpc7450_pmu(void)
return register_power_pmu(&mpc7450_pmu);
}
-early_initcall(init_mpc7450_pmu);
+arch_initcall(init_mpc7450_pmu);
diff --git a/trunk/arch/powerpc/kernel/power4-pmu.c b/trunk/arch/powerpc/kernel/power4-pmu.c
index ead8b3c2649e..2a361cdda635 100644
--- a/trunk/arch/powerpc/kernel/power4-pmu.c
+++ b/trunk/arch/powerpc/kernel/power4-pmu.c
@@ -613,4 +613,4 @@ static int init_power4_pmu(void)
return register_power_pmu(&power4_pmu);
}
-early_initcall(init_power4_pmu);
+arch_initcall(init_power4_pmu);
diff --git a/trunk/arch/powerpc/kernel/power5+-pmu.c b/trunk/arch/powerpc/kernel/power5+-pmu.c
index eca0ac595cb6..199de527d411 100644
--- a/trunk/arch/powerpc/kernel/power5+-pmu.c
+++ b/trunk/arch/powerpc/kernel/power5+-pmu.c
@@ -682,4 +682,4 @@ static int init_power5p_pmu(void)
return register_power_pmu(&power5p_pmu);
}
-early_initcall(init_power5p_pmu);
+arch_initcall(init_power5p_pmu);
diff --git a/trunk/arch/powerpc/kernel/power5-pmu.c b/trunk/arch/powerpc/kernel/power5-pmu.c
index d5ff0f64a5e6..98b6a729a9dd 100644
--- a/trunk/arch/powerpc/kernel/power5-pmu.c
+++ b/trunk/arch/powerpc/kernel/power5-pmu.c
@@ -621,4 +621,4 @@ static int init_power5_pmu(void)
return register_power_pmu(&power5_pmu);
}
-early_initcall(init_power5_pmu);
+arch_initcall(init_power5_pmu);
diff --git a/trunk/arch/powerpc/kernel/power6-pmu.c b/trunk/arch/powerpc/kernel/power6-pmu.c
index 31603927e376..84a607bda8fb 100644
--- a/trunk/arch/powerpc/kernel/power6-pmu.c
+++ b/trunk/arch/powerpc/kernel/power6-pmu.c
@@ -544,4 +544,4 @@ static int init_power6_pmu(void)
return register_power_pmu(&power6_pmu);
}
-early_initcall(init_power6_pmu);
+arch_initcall(init_power6_pmu);
diff --git a/trunk/arch/powerpc/kernel/power7-pmu.c b/trunk/arch/powerpc/kernel/power7-pmu.c
index 593740fcb799..852f7b7f6b40 100644
--- a/trunk/arch/powerpc/kernel/power7-pmu.c
+++ b/trunk/arch/powerpc/kernel/power7-pmu.c
@@ -369,4 +369,4 @@ static int init_power7_pmu(void)
return register_power_pmu(&power7_pmu);
}
-early_initcall(init_power7_pmu);
+arch_initcall(init_power7_pmu);
diff --git a/trunk/arch/powerpc/kernel/ppc970-pmu.c b/trunk/arch/powerpc/kernel/ppc970-pmu.c
index 9a6e093858fe..3fee685de4df 100644
--- a/trunk/arch/powerpc/kernel/ppc970-pmu.c
+++ b/trunk/arch/powerpc/kernel/ppc970-pmu.c
@@ -494,4 +494,4 @@ static int init_ppc970_pmu(void)
return register_power_pmu(&ppc970_pmu);
}
-early_initcall(init_ppc970_pmu);
+arch_initcall(init_ppc970_pmu);
diff --git a/trunk/arch/powerpc/kernel/setup_64.c b/trunk/arch/powerpc/kernel/setup_64.c
index ce6f61c6f871..2a178b0ebcdf 100644
--- a/trunk/arch/powerpc/kernel/setup_64.c
+++ b/trunk/arch/powerpc/kernel/setup_64.c
@@ -497,8 +497,9 @@ static void __init emergency_stack_init(void)
}
/*
- * Called into from start_kernel this initializes bootmem, which is used
- * to manage page allocation until mem_init is called.
+ * Called into from start_kernel, after lock_kernel has been called.
+ * Initializes bootmem, which is unsed to manage page allocation until
+ * mem_init is called.
*/
void __init setup_arch(char **cmdline_p)
{
diff --git a/trunk/arch/powerpc/kernel/sys_ppc32.c b/trunk/arch/powerpc/kernel/sys_ppc32.c
index 4e5bf1edc0f2..b1b6043a56c4 100644
--- a/trunk/arch/powerpc/kernel/sys_ppc32.c
+++ b/trunk/arch/powerpc/kernel/sys_ppc32.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/powerpc/mm/hash_utils_64.c b/trunk/arch/powerpc/mm/hash_utils_64.c
index 5e9584405c45..83f534d862db 100644
--- a/trunk/arch/powerpc/mm/hash_utils_64.c
+++ b/trunk/arch/powerpc/mm/hash_utils_64.c
@@ -1123,7 +1123,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
else
#endif /* CONFIG_PPC_HAS_HASH_64K */
rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
- subpage_protection(mm, ea));
+ subpage_protection(pgdir, ea));
/* Dump some info in case of hash insertion failure, they should
* never happen so it is really useful to know if/when they do
diff --git a/trunk/arch/powerpc/mm/tlb_low_64e.S b/trunk/arch/powerpc/mm/tlb_low_64e.S
index 8526bd9d2aa3..8b04c54e596f 100644
--- a/trunk/arch/powerpc/mm/tlb_low_64e.S
+++ b/trunk/arch/powerpc/mm/tlb_low_64e.S
@@ -138,11 +138,8 @@
cmpldi cr0,r15,0 /* Check for user region */
std r14,EX_TLB_ESR(r12) /* write crazy -1 to frame */
beq normal_tlb_miss
-
- li r11,_PAGE_PRESENT|_PAGE_BAP_SX /* Base perm */
- oris r11,r11,_PAGE_ACCESSED@h
/* XXX replace the RMW cycles with immediate loads + writes */
- mfspr r10,SPRN_MAS1
+1: mfspr r10,SPRN_MAS1
cmpldi cr0,r15,8 /* Check for vmalloc region */
rlwinm r10,r10,0,16,1 /* Clear TID */
mtspr SPRN_MAS1,r10
diff --git a/trunk/arch/powerpc/mm/tlb_nohash.c b/trunk/arch/powerpc/mm/tlb_nohash.c
index 2a030d89bbc6..36c0c449a899 100644
--- a/trunk/arch/powerpc/mm/tlb_nohash.c
+++ b/trunk/arch/powerpc/mm/tlb_nohash.c
@@ -585,6 +585,6 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
/* Finally limit subsequent allocations */
- memblock_set_current_limit(first_memblock_base + ppc64_rma_size);
+ memblock_set_current_limit(ppc64_memblock_base + ppc64_rma_size);
}
#endif /* CONFIG_PPC64 */
diff --git a/trunk/arch/powerpc/platforms/pseries/Kconfig b/trunk/arch/powerpc/platforms/pseries/Kconfig
index 3139814f6439..c667f0f02c34 100644
--- a/trunk/arch/powerpc/platforms/pseries/Kconfig
+++ b/trunk/arch/powerpc/platforms/pseries/Kconfig
@@ -47,12 +47,6 @@ config LPARCFG
config PPC_PSERIES_DEBUG
depends on PPC_PSERIES && PPC_EARLY_DEBUG
bool "Enable extra debug logging in platforms/pseries"
- help
- Say Y here if you want the pseries core to produce a bunch of
- debug messages to the system log. Select this if you are having a
- problem with the pseries core and want to see more of what is
- going on. This does not enable debugging in lpar.c, which must
- be manually done due to its verbosity.
default y
config PPC_SMLPAR
diff --git a/trunk/arch/powerpc/platforms/pseries/eeh.c b/trunk/arch/powerpc/platforms/pseries/eeh.c
index 17a11c82e6f8..34b7dc12e731 100644
--- a/trunk/arch/powerpc/platforms/pseries/eeh.c
+++ b/trunk/arch/powerpc/platforms/pseries/eeh.c
@@ -21,6 +21,8 @@
* Please address comments and feedback to Linas Vepstas
*/
+#undef DEBUG
+
#include
#include
#include
diff --git a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c
index 5fcc92a12d3e..4b7a062dee15 100644
--- a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -25,6 +25,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#undef DEBUG
+
#include
#include
#include
diff --git a/trunk/arch/s390/Kconfig.debug b/trunk/arch/s390/Kconfig.debug
index 05221b13ffb1..45e0c6199f36 100644
--- a/trunk/arch/s390/Kconfig.debug
+++ b/trunk/arch/s390/Kconfig.debug
@@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-config STRICT_DEVMEM
- def_bool y
- prompt "Filter access to /dev/mem"
- ---help---
- This option restricts access to /dev/mem. If this option is
- disabled, you allow userspace access to all memory, including
- kernel and userspace memory. Accidental memory access is likely
- to be disastrous.
- Memory access is required for experts who want to debug the kernel.
-
- If you are unsure, say Y.
-
config DEBUG_STRICT_USER_COPY_CHECKS
bool "Strict user copy size checks"
---help---
diff --git a/trunk/arch/s390/include/asm/page.h b/trunk/arch/s390/include/asm/page.h
index 3c987e9ec8d6..a8729ea7e9ac 100644
--- a/trunk/arch/s390/include/asm/page.h
+++ b/trunk/arch/s390/include/asm/page.h
@@ -130,11 +130,6 @@ struct page;
void arch_free_page(struct page *page, int order);
void arch_alloc_page(struct page *page, int order);
-static inline int devmem_is_allowed(unsigned long pfn)
-{
- return 0;
-}
-
#define HAVE_ARCH_FREE_PAGE
#define HAVE_ARCH_ALLOC_PAGE
diff --git a/trunk/arch/s390/kernel/compat_linux.c b/trunk/arch/s390/kernel/compat_linux.c
index 53acaa86dd94..1e6449c79ab6 100644
--- a/trunk/arch/s390/kernel/compat_linux.c
+++ b/trunk/arch/s390/kernel/compat_linux.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/s390/kernel/kprobes.c b/trunk/arch/s390/kernel/kprobes.c
index 2564793ec2b6..d60fc4398516 100644
--- a/trunk/arch/s390/kernel/kprobes.c
+++ b/trunk/arch/s390/kernel/kprobes.c
@@ -30,7 +30,6 @@
#include
#include
#include
-#include
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -213,7 +212,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
/* Set the PER control regs, turns on single step for this address */
__ctl_load(kprobe_per_regs, 9, 11);
regs->psw.mask |= PSW_MASK_PER;
- regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
+ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
}
static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
@@ -240,7 +239,7 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
__get_cpu_var(current_kprobe) = p;
/* Save the interrupt and per flags */
kcb->kprobe_saved_imask = regs->psw.mask &
- (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
+ (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
/* Save the control regs that govern PER */
__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
}
@@ -317,6 +316,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
return 1;
ss_probe:
+ if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
+ local_irq_disable();
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
@@ -349,7 +350,6 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
- kprobe_opcode_t *correct_ret_addr = NULL;
INIT_HLIST_HEAD(&empty_rp);
kretprobe_hash_lock(current, &head, &flags);
@@ -372,32 +372,10 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
/* another task is sharing our hash bucket */
continue;
- orig_ret_address = (unsigned long)ri->ret_addr;
-
- if (orig_ret_address != trampoline_address)
- /*
- * This is the real return address. Any other
- * instances associated with this task are for
- * other calls deeper on the call stack
- */
- break;
- }
-
- kretprobe_assert(ri, orig_ret_address, trampoline_address);
-
- correct_ret_addr = ri->ret_addr;
- hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current)
- /* another task is sharing our hash bucket */
- continue;
-
- orig_ret_address = (unsigned long)ri->ret_addr;
-
- if (ri->rp && ri->rp->handler) {
- ri->ret_addr = correct_ret_addr;
+ if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
- }
+ orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address) {
@@ -409,7 +387,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
break;
}
}
-
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
reset_current_kprobe();
@@ -487,6 +465,8 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
goto out;
}
reset_current_kprobe();
+ if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
+ local_irq_enable();
out:
preempt_enable_no_resched();
@@ -502,7 +482,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
return 1;
}
-static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -528,6 +508,8 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
restore_previous_kprobe(kcb);
else {
reset_current_kprobe();
+ if (regs->psw.mask & (PSW_MASK_PER | PSW_MASK_IO))
+ local_irq_enable();
}
preempt_enable_no_resched();
break;
@@ -571,18 +553,6 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
return 0;
}
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
-{
- int ret;
-
- if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
- local_irq_disable();
- ret = kprobe_trap_handler(regs, trapnr);
- if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
- local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
- return ret;
-}
-
/*
* Wrapper routine to for handling exceptions.
*/
@@ -590,12 +560,8 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
{
struct die_args *args = (struct die_args *)data;
- struct pt_regs *regs = args->regs;
int ret = NOTIFY_DONE;
- if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
- local_irq_disable();
-
switch (val) {
case DIE_BPT:
if (kprobe_handler(args->regs))
@@ -606,17 +572,16 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
ret = NOTIFY_STOP;
break;
case DIE_TRAP:
- if (!preemptible() && kprobe_running() &&
- kprobe_trap_handler(args->regs, args->trapnr))
+ /* kprobe_running() needs smp_processor_id() */
+ preempt_disable();
+ if (kprobe_running() &&
+ kprobe_fault_handler(args->regs, args->trapnr))
ret = NOTIFY_STOP;
+ preempt_enable();
break;
default:
break;
}
-
- if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
- local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
-
return ret;
}
@@ -630,7 +595,6 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
/* setup return addr to the jprobe handler routine */
regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
- regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
/* r14 is the function return address */
kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
diff --git a/trunk/arch/s390/mm/gup.c b/trunk/arch/s390/mm/gup.c
index 45b405ca2567..38e641cdd977 100644
--- a/trunk/arch/s390/mm/gup.c
+++ b/trunk/arch/s390/mm/gup.c
@@ -20,17 +20,18 @@
static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
- unsigned long mask;
+ unsigned long mask, result;
pte_t *ptep, pte;
struct page *page;
- mask = (write ? _PAGE_RO : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
+ result = write ? 0 : _PAGE_RO;
+ mask = result | _PAGE_INVALID | _PAGE_SPECIAL;
ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
do {
pte = *ptep;
barrier();
- if ((pte_val(pte) & mask) != 0)
+ if ((pte_val(pte) & mask) != result)
return 0;
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
page = pte_page(pte);
diff --git a/trunk/arch/sh/kernel/cpu/sh4/perf_event.c b/trunk/arch/sh/kernel/cpu/sh4/perf_event.c
index 748955df018d..dbf3b4bb71fe 100644
--- a/trunk/arch/sh/kernel/cpu/sh4/perf_event.c
+++ b/trunk/arch/sh/kernel/cpu/sh4/perf_event.c
@@ -250,4 +250,4 @@ static int __init sh7750_pmu_init(void)
return register_sh_pmu(&sh7750_pmu);
}
-early_initcall(sh7750_pmu_init);
+arch_initcall(sh7750_pmu_init);
diff --git a/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c b/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c
index 17e6bebfede0..580276525731 100644
--- a/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c
+++ b/trunk/arch/sh/kernel/cpu/sh4a/perf_event.c
@@ -284,4 +284,4 @@ static int __init sh4a_pmu_init(void)
return register_sh_pmu(&sh4a_pmu);
}
-early_initcall(sh4a_pmu_init);
+arch_initcall(sh4a_pmu_init);
diff --git a/trunk/arch/sparc/include/asm/perf_event.h b/trunk/arch/sparc/include/asm/perf_event.h
index 4d3dbe3703e9..6e8bfa1786da 100644
--- a/trunk/arch/sparc/include/asm/perf_event.h
+++ b/trunk/arch/sparc/include/asm/perf_event.h
@@ -4,6 +4,8 @@
#ifdef CONFIG_PERF_EVENTS
#include
+extern void init_hw_perf_events(void);
+
#define perf_arch_fetch_caller_regs(regs, ip) \
do { \
unsigned long _pstate, _asi, _pil, _i7, _fp; \
@@ -24,6 +26,8 @@ do { \
(regs)->u_regs[UREG_I6] = _fp; \
(regs)->u_regs[UREG_I7] = _i7; \
} while (0)
+#else
+static inline void init_hw_perf_events(void) { }
#endif
#endif
diff --git a/trunk/arch/sparc/kernel/leon_smp.c b/trunk/arch/sparc/kernel/leon_smp.c
index 16582d85368a..7524689b03d2 100644
--- a/trunk/arch/sparc/kernel/leon_smp.c
+++ b/trunk/arch/sparc/kernel/leon_smp.c
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/sparc/kernel/nmi.c b/trunk/arch/sparc/kernel/nmi.c
index 300f810142f5..a4bd7ba74c89 100644
--- a/trunk/arch/sparc/kernel/nmi.c
+++ b/trunk/arch/sparc/kernel/nmi.c
@@ -270,6 +270,8 @@ int __init nmi_init(void)
atomic_set(&nmi_active, -1);
}
}
+ if (!err)
+ init_hw_perf_events();
return err;
}
diff --git a/trunk/arch/sparc/kernel/perf_event.c b/trunk/arch/sparc/kernel/perf_event.c
index 75c5b1263970..0d6deb55a2ae 100644
--- a/trunk/arch/sparc/kernel/perf_event.c
+++ b/trunk/arch/sparc/kernel/perf_event.c
@@ -1307,23 +1307,20 @@ static bool __init supported_pmu(void)
return false;
}
-int __init init_hw_perf_events(void)
+void __init init_hw_perf_events(void)
{
pr_info("Performance events: ");
if (!supported_pmu()) {
pr_cont("No support for PMU type '%s'\n", sparc_pmu_type);
- return 0;
+ return;
}
pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type);
perf_pmu_register(&pmu);
register_die_notifier(&perf_event_nmi_notifier);
-
- return 0;
}
-early_initcall(init_hw_perf_event);
void perf_callchain_kernel(struct perf_callchain_entry *entry,
struct pt_regs *regs)
diff --git a/trunk/arch/sparc/kernel/sys_sparc32.c b/trunk/arch/sparc/kernel/sys_sparc32.c
index 6db18c6927fb..e6375a750d9a 100644
--- a/trunk/arch/sparc/kernel/sys_sparc32.c
+++ b/trunk/arch/sparc/kernel/sys_sparc32.c
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/sparc/kernel/sys_sparc_32.c b/trunk/arch/sparc/kernel/sys_sparc_32.c
index 42b282fa6112..675c9e11ada5 100644
--- a/trunk/arch/sparc/kernel/sys_sparc_32.c
+++ b/trunk/arch/sparc/kernel/sys_sparc_32.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/trunk/arch/sparc/kernel/unaligned_32.c b/trunk/arch/sparc/kernel/unaligned_32.c
index 4491f4cb2695..12b9f352595f 100644
--- a/trunk/arch/sparc/kernel/unaligned_32.c
+++ b/trunk/arch/sparc/kernel/unaligned_32.c
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
enum direction {
diff --git a/trunk/arch/sparc/kernel/windows.c b/trunk/arch/sparc/kernel/windows.c
index 3107381e576d..b351770cbdd6 100644
--- a/trunk/arch/sparc/kernel/windows.c
+++ b/trunk/arch/sparc/kernel/windows.c
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
diff --git a/trunk/arch/tile/kernel/compat.c b/trunk/arch/tile/kernel/compat.c
index dbc213adf5e1..67617a05e602 100644
--- a/trunk/arch/tile/kernel/compat.c
+++ b/trunk/arch/tile/kernel/compat.c
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/tile/kernel/compat_signal.c b/trunk/arch/tile/kernel/compat_signal.c
index 543d6a33aa26..fb64b99959d4 100644
--- a/trunk/arch/tile/kernel/compat_signal.c
+++ b/trunk/arch/tile/kernel/compat_signal.c
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/tile/kernel/signal.c b/trunk/arch/tile/kernel/signal.c
index 757407e36696..687719d4abd1 100644
--- a/trunk/arch/tile/kernel/signal.c
+++ b/trunk/arch/tile/kernel/signal.c
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/tile/kernel/smpboot.c b/trunk/arch/tile/kernel/smpboot.c
index b949edcec200..74d62d098edf 100644
--- a/trunk/arch/tile/kernel/smpboot.c
+++ b/trunk/arch/tile/kernel/smpboot.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/tile/kernel/sys.c b/trunk/arch/tile/kernel/sys.c
index e2187d24a9b4..7e764669a022 100644
--- a/trunk/arch/tile/kernel/sys.c
+++ b/trunk/arch/tile/kernel/sys.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/tile/mm/fault.c b/trunk/arch/tile/mm/fault.c
index dcebfc831cd6..f295b4ac941d 100644
--- a/trunk/arch/tile/mm/fault.c
+++ b/trunk/arch/tile/mm/fault.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/tile/mm/hugetlbpage.c b/trunk/arch/tile/mm/hugetlbpage.c
index 201a582c4137..24688b697a8d 100644
--- a/trunk/arch/tile/mm/hugetlbpage.c
+++ b/trunk/arch/tile/mm/hugetlbpage.c
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/um/kernel/exec.c b/trunk/arch/um/kernel/exec.c
index 09bd7b585726..340268be00b5 100644
--- a/trunk/arch/um/kernel/exec.c
+++ b/trunk/arch/um/kernel/exec.c
@@ -5,6 +5,7 @@
#include "linux/stddef.h"
#include "linux/fs.h"
+#include "linux/smp_lock.h"
#include "linux/ptrace.h"
#include "linux/sched.h"
#include "linux/slab.h"
diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig
index e330da21b84f..e8327686d3c5 100644
--- a/trunk/arch/x86/Kconfig
+++ b/trunk/arch/x86/Kconfig
@@ -21,7 +21,7 @@ config X86
select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_IDE
select HAVE_OPROFILE
- select HAVE_PERF_EVENTS
+ select HAVE_PERF_EVENTS if (!M386 && !M486)
select HAVE_IRQ_WORK
select HAVE_IOREMAP_PROT
select HAVE_KPROBES
diff --git a/trunk/arch/x86/ia32/sys_ia32.c b/trunk/arch/x86/ia32/sys_ia32.c
index 5852519b2d0f..849813f398e7 100644
--- a/trunk/arch/x86/ia32/sys_ia32.c
+++ b/trunk/arch/x86/ia32/sys_ia32.c
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/x86/include/asm/kdebug.h b/trunk/arch/x86/include/asm/kdebug.h
index f23eb2528464..5bdfca86581b 100644
--- a/trunk/arch/x86/include/asm/kdebug.h
+++ b/trunk/arch/x86/include/asm/kdebug.h
@@ -28,7 +28,7 @@ extern void die(const char *, struct pt_regs *,long);
extern int __must_check __die(const char *, struct pt_regs *, long);
extern void show_registers(struct pt_regs *regs);
extern void show_trace(struct task_struct *t, struct pt_regs *regs,
- unsigned long *sp);
+ unsigned long *sp, unsigned long bp);
extern void __show_regs(struct pt_regs *regs, int all);
extern void show_regs(struct pt_regs *regs);
extern unsigned long oops_begin(void);
diff --git a/trunk/arch/x86/include/asm/nmi.h b/trunk/arch/x86/include/asm/nmi.h
index 3545838cddeb..932f0f86b4b7 100644
--- a/trunk/arch/x86/include/asm/nmi.h
+++ b/trunk/arch/x86/include/asm/nmi.h
@@ -7,13 +7,39 @@
#ifdef ARCH_HAS_NMI_WATCHDOG
+/**
+ * do_nmi_callback
+ *
+ * Check to see if a callback exists and execute it. Return 1
+ * if the handler exists and was handled successfully.
+ */
+int do_nmi_callback(struct pt_regs *regs, int cpu);
+
extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
+extern int check_nmi_watchdog(void);
+#if !defined(CONFIG_LOCKUP_DETECTOR)
+extern int nmi_watchdog_enabled;
+#endif
extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
extern int reserve_perfctr_nmi(unsigned int);
extern void release_perfctr_nmi(unsigned int);
extern int reserve_evntsel_nmi(unsigned int);
extern void release_evntsel_nmi(unsigned int);
+extern void setup_apic_nmi_watchdog(void *);
+extern void stop_apic_nmi_watchdog(void *);
+extern void disable_timer_nmi_watchdog(void);
+extern void enable_timer_nmi_watchdog(void);
+extern int nmi_watchdog_tick(struct pt_regs *regs, unsigned reason);
+extern void cpu_nmi_set_wd_enabled(void);
+
+extern atomic_t nmi_active;
+extern unsigned int nmi_watchdog;
+#define NMI_NONE 0
+#define NMI_IO_APIC 1
+#define NMI_LOCAL_APIC 2
+#define NMI_INVALID 3
+
struct ctl_table;
extern int proc_nmi_enabled(struct ctl_table *, int ,
void __user *, size_t *, loff_t *);
@@ -21,8 +47,33 @@ extern int unknown_nmi_panic;
void arch_trigger_all_cpu_backtrace(void);
#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
+
+static inline void localise_nmi_watchdog(void)
+{
+ if (nmi_watchdog == NMI_IO_APIC)
+ nmi_watchdog = NMI_LOCAL_APIC;
+}
+
+/* check if nmi_watchdog is active (ie was specified at boot) */
+static inline int nmi_watchdog_active(void)
+{
+ /*
+ * actually it should be:
+ * return (nmi_watchdog == NMI_LOCAL_APIC ||
+ * nmi_watchdog == NMI_IO_APIC)
+ * but since they are power of two we could use a
+ * cheaper way --cvg
+ */
+ return nmi_watchdog & (NMI_LOCAL_APIC | NMI_IO_APIC);
+}
#endif
+void lapic_watchdog_stop(void);
+int lapic_watchdog_init(unsigned nmi_hz);
+int lapic_wd_event(unsigned nmi_hz);
+unsigned lapic_adjust_nmi_hz(unsigned hz);
+void disable_lapic_nmi_watchdog(void);
+void enable_lapic_nmi_watchdog(void);
void stop_nmi(void);
void restart_nmi(void);
diff --git a/trunk/arch/x86/include/asm/paravirt.h b/trunk/arch/x86/include/asm/paravirt.h
index ef9975812c77..18e3b8a8709f 100644
--- a/trunk/arch/x86/include/asm/paravirt.h
+++ b/trunk/arch/x86/include/asm/paravirt.h
@@ -824,27 +824,27 @@ static __always_inline void arch_spin_unlock(struct arch_spinlock *lock)
#define __PV_IS_CALLEE_SAVE(func) \
((struct paravirt_callee_save) { func })
-static inline notrace unsigned long arch_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
{
return PVOP_CALLEE0(unsigned long, pv_irq_ops.save_fl);
}
-static inline notrace void arch_local_irq_restore(unsigned long f)
+static inline void arch_local_irq_restore(unsigned long f)
{
PVOP_VCALLEE1(pv_irq_ops.restore_fl, f);
}
-static inline notrace void arch_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
{
PVOP_VCALLEE0(pv_irq_ops.irq_disable);
}
-static inline notrace void arch_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
{
PVOP_VCALLEE0(pv_irq_ops.irq_enable);
}
-static inline notrace unsigned long arch_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
{
unsigned long f;
diff --git a/trunk/arch/x86/include/asm/perf_event.h b/trunk/arch/x86/include/asm/perf_event.h
index d9d4dae305f6..550e26b1dbb3 100644
--- a/trunk/arch/x86/include/asm/perf_event.h
+++ b/trunk/arch/x86/include/asm/perf_event.h
@@ -125,6 +125,7 @@ union cpuid10_edx {
#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */
#ifdef CONFIG_PERF_EVENTS
+extern void init_hw_perf_events(void);
extern void perf_events_lapic_init(void);
#define PERF_EVENT_INDEX_OFFSET 0
@@ -155,6 +156,7 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
}
#else
+static inline void init_hw_perf_events(void) { }
static inline void perf_events_lapic_init(void) { }
#endif
diff --git a/trunk/arch/x86/include/asm/perf_event_p4.h b/trunk/arch/x86/include/asm/perf_event_p4.h
index 295e2ff18a6a..a70cd216be5d 100644
--- a/trunk/arch/x86/include/asm/perf_event_p4.h
+++ b/trunk/arch/x86/include/asm/perf_event_p4.h
@@ -744,6 +744,14 @@ enum P4_ESCR_EMASKS {
};
/*
+ * P4 PEBS specifics (Replay Event only)
+ *
+ * Format (bits):
+ * 0-6: metric from P4_PEBS_METRIC enum
+ * 7 : reserved
+ * 8 : reserved
+ * 9-11 : reserved
+ *
* Note we have UOP and PEBS bits reserved for now
* just in case if we will need them once
*/
@@ -780,60 +788,5 @@ enum P4_PEBS_METRIC {
P4_PEBS_METRIC__max
};
-/*
- * Notes on internal configuration of ESCR+CCCR tuples
- *
- * Since P4 has quite the different architecture of
- * performance registers in compare with "architectural"
- * once and we have on 64 bits to keep configuration
- * of performance event, the following trick is used.
- *
- * 1) Since both ESCR and CCCR registers have only low
- * 32 bits valuable, we pack them into a single 64 bit
- * configuration. Low 32 bits of such config correspond
- * to low 32 bits of CCCR register and high 32 bits
- * correspond to low 32 bits of ESCR register.
- *
- * 2) The meaning of every bit of such config field can
- * be found in Intel SDM but it should be noted that
- * we "borrow" some reserved bits for own usage and
- * clean them or set to a proper value when we do
- * a real write to hardware registers.
- *
- * 3) The format of bits of config is the following
- * and should be either 0 or set to some predefined
- * values:
- *
- * Low 32 bits
- * -----------
- * 0-6: P4_PEBS_METRIC enum
- * 7-11: reserved
- * 12: reserved (Enable)
- * 13-15: reserved (ESCR select)
- * 16-17: Active Thread
- * 18: Compare
- * 19: Complement
- * 20-23: Threshold
- * 24: Edge
- * 25: reserved (FORCE_OVF)
- * 26: reserved (OVF_PMI_T0)
- * 27: reserved (OVF_PMI_T1)
- * 28-29: reserved
- * 30: reserved (Cascade)
- * 31: reserved (OVF)
- *
- * High 32 bits
- * ------------
- * 0: reserved (T1_USR)
- * 1: reserved (T1_OS)
- * 2: reserved (T0_USR)
- * 3: reserved (T0_OS)
- * 4: Tag Enable
- * 5-8: Tag Value
- * 9-24: Event Mask (may use P4_ESCR_EMASK_BIT helper)
- * 25-30: enum P4_EVENTS
- * 31: reserved (HT thread)
- */
-
#endif /* PERF_EVENT_P4_H */
diff --git a/trunk/arch/x86/include/asm/smpboot_hooks.h b/trunk/arch/x86/include/asm/smpboot_hooks.h
index 6c22bf353f26..1def60114906 100644
--- a/trunk/arch/x86/include/asm/smpboot_hooks.h
+++ b/trunk/arch/x86/include/asm/smpboot_hooks.h
@@ -48,6 +48,7 @@ static inline void __init smpboot_setup_io_apic(void)
setup_IO_APIC();
else {
nr_ioapics = 0;
+ localise_nmi_watchdog();
}
#endif
}
diff --git a/trunk/arch/x86/include/asm/stacktrace.h b/trunk/arch/x86/include/asm/stacktrace.h
index 52b5c7ed3608..2b16a2ad23dc 100644
--- a/trunk/arch/x86/include/asm/stacktrace.h
+++ b/trunk/arch/x86/include/asm/stacktrace.h
@@ -7,7 +7,6 @@
#define _ASM_X86_STACKTRACE_H
#include
-#include
extern int kstack_depth_to_print;
@@ -47,7 +46,7 @@ struct stacktrace_ops {
};
void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
- unsigned long *stack,
+ unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data);
#ifdef CONFIG_X86_32
@@ -58,39 +57,13 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#endif
-#ifdef CONFIG_FRAME_POINTER
-static inline unsigned long
-stack_frame(struct task_struct *task, struct pt_regs *regs)
-{
- unsigned long bp;
-
- if (regs)
- return regs->bp;
-
- if (task == current) {
- /* Grab bp right from our regs */
- get_bp(bp);
- return bp;
- }
-
- /* bp is the last reg pushed by switch_to */
- return *(unsigned long *)task->thread.sp;
-}
-#else
-static inline unsigned long
-stack_frame(struct task_struct *task, struct pt_regs *regs)
-{
- return 0;
-}
-#endif
-
extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, char *log_lvl);
+ unsigned long *stack, unsigned long bp, char *log_lvl);
extern void
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, char *log_lvl);
+ unsigned long *sp, unsigned long bp, char *log_lvl);
extern unsigned int code_bytes;
diff --git a/trunk/arch/x86/include/asm/timer.h b/trunk/arch/x86/include/asm/timer.h
index fa7b9176b76c..5469630b27f5 100644
--- a/trunk/arch/x86/include/asm/timer.h
+++ b/trunk/arch/x86/include/asm/timer.h
@@ -10,6 +10,12 @@
unsigned long long native_sched_clock(void);
extern int recalibrate_cpu_khz(void);
+#if defined(CONFIG_X86_32) && defined(CONFIG_X86_IO_APIC)
+extern int timer_ack;
+#else
+# define timer_ack (0)
+#endif
+
extern int no_timer_check;
/* Accelerators for sched_clock()
diff --git a/trunk/arch/x86/kernel/apic/Makefile b/trunk/arch/x86/kernel/apic/Makefile
index 3966b564ea47..910f20b457c4 100644
--- a/trunk/arch/x86/kernel/apic/Makefile
+++ b/trunk/arch/x86/kernel/apic/Makefile
@@ -3,7 +3,10 @@
#
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o
-obj-y += hw_nmi.o
+ifneq ($(CONFIG_HARDLOCKUP_DETECTOR),y)
+obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o
+endif
+obj-$(CONFIG_HARDLOCKUP_DETECTOR) += hw_nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_SMP) += ipi.o
diff --git a/trunk/arch/x86/kernel/apic/apic.c b/trunk/arch/x86/kernel/apic/apic.c
index e9e2a93783f9..3f838d537392 100644
--- a/trunk/arch/x86/kernel/apic/apic.c
+++ b/trunk/arch/x86/kernel/apic/apic.c
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
@@ -798,7 +799,11 @@ void __init setup_boot_APIC_clock(void)
* PIT/HPET going. Otherwise register lapic as a dummy
* device.
*/
- lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+ if (nmi_watchdog != NMI_IO_APIC)
+ lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+ else
+ pr_warning("APIC timer registered as dummy,"
+ " due to nmi_watchdog=%d!\n", nmi_watchdog);
/* Setup the lapic or request the broadcast */
setup_APIC_timer();
@@ -1382,6 +1387,7 @@ void __cpuinit end_local_APIC_setup(void)
}
#endif
+ setup_apic_nmi_watchdog(NULL);
apic_pm_activate();
}
@@ -1744,10 +1750,17 @@ int __init APIC_init_uniprocessor(void)
setup_IO_APIC();
else {
nr_ioapics = 0;
+ localise_nmi_watchdog();
}
+#else
+ localise_nmi_watchdog();
#endif
x86_init.timers.setup_percpu_clockev();
+#ifdef CONFIG_X86_64
+ check_nmi_watchdog();
+#endif
+
return 0;
}
diff --git a/trunk/arch/x86/kernel/apic/hw_nmi.c b/trunk/arch/x86/kernel/apic/hw_nmi.c
index a0e71cb4fa9c..cefd6942f0e9 100644
--- a/trunk/arch/x86/kernel/apic/hw_nmi.c
+++ b/trunk/arch/x86/kernel/apic/hw_nmi.c
@@ -17,18 +17,15 @@
#include
#include
-#ifdef CONFIG_HARDLOCKUP_DETECTOR
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
u64 hw_nmi_get_sample_period(void)
{
return (u64)(cpu_khz) * 1000 * 60;
}
-#endif
-
-/* For reliability, we're prepared to waste bits here. */
-static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
-
-#ifdef arch_trigger_all_cpu_backtrace
+#ifdef ARCH_HAS_NMI_WATCHDOG
void arch_trigger_all_cpu_backtrace(void)
{
int i;
@@ -95,4 +92,16 @@ early_initcall(register_trigger_all_cpu_backtrace);
#endif
/* STUB calls to mimic old nmi_watchdog behaviour */
+#if defined(CONFIG_X86_LOCAL_APIC)
+unsigned int nmi_watchdog = NMI_NONE;
+EXPORT_SYMBOL(nmi_watchdog);
+void acpi_nmi_enable(void) { return; }
+void acpi_nmi_disable(void) { return; }
+#endif
+atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+EXPORT_SYMBOL(nmi_active);
int unknown_nmi_panic;
+void cpu_nmi_set_wd_enabled(void) { return; }
+void stop_apic_nmi_watchdog(void *unused) { return; }
+void setup_apic_nmi_watchdog(void *unused) { return; }
+int __init check_nmi_watchdog(void) { return 0; }
diff --git a/trunk/arch/x86/kernel/apic/io_apic.c b/trunk/arch/x86/kernel/apic/io_apic.c
index e4a040c28de1..7cc0a721f628 100644
--- a/trunk/arch/x86/kernel/apic/io_apic.c
+++ b/trunk/arch/x86/kernel/apic/io_apic.c
@@ -54,6 +54,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -2642,6 +2643,24 @@ static void lapic_register_intr(int irq)
"edge");
}
+static void __init setup_nmi(void)
+{
+ /*
+ * Dirty trick to enable the NMI watchdog ...
+ * We put the 8259A master into AEOI mode and
+ * unmask on all local APICs LVT0 as NMI.
+ *
+ * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
+ * is from Maciej W. Rozycki - so we do not have to EOI from
+ * the NMI handler or the timer interrupt.
+ */
+ apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ...");
+
+ enable_NMI_through_LVT0();
+
+ apic_printk(APIC_VERBOSE, " done.\n");
+}
+
/*
* This looks a bit hackish but it's about the only one way of sending
* a few INTA cycles to 8259As and any associated glue logic. ICR does
@@ -2747,6 +2766,15 @@ static inline void __init check_timer(void)
*/
apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
legacy_pic->init(1);
+#ifdef CONFIG_X86_32
+ {
+ unsigned int ver;
+
+ ver = apic_read(APIC_LVR);
+ ver = GET_APIC_VERSION(ver);
+ timer_ack = (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver));
+ }
+#endif
pin1 = find_isa_irq_pin(0, mp_INT);
apic1 = find_isa_irq_apic(0, mp_INT);
@@ -2794,6 +2822,10 @@ static inline void __init check_timer(void)
unmask_ioapic(cfg);
}
if (timer_irq_works()) {
+ if (nmi_watchdog == NMI_IO_APIC) {
+ setup_nmi();
+ legacy_pic->unmask(0);
+ }
if (disable_timer_pin_1 > 0)
clear_IO_APIC_pin(0, pin1);
goto out;
@@ -2819,6 +2851,11 @@ static inline void __init check_timer(void)
if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
timer_through_8259 = 1;
+ if (nmi_watchdog == NMI_IO_APIC) {
+ legacy_pic->mask(0);
+ setup_nmi();
+ legacy_pic->unmask(0);
+ }
goto out;
}
/*
@@ -2830,6 +2867,15 @@ static inline void __init check_timer(void)
apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n");
}
+ if (nmi_watchdog == NMI_IO_APIC) {
+ apic_printk(APIC_QUIET, KERN_WARNING "timer doesn't work "
+ "through the IO-APIC - disabling NMI Watchdog!\n");
+ nmi_watchdog = NMI_NONE;
+ }
+#ifdef CONFIG_X86_32
+ timer_ack = 0;
+#endif
+
apic_printk(APIC_QUIET, KERN_INFO
"...trying to set up timer as Virtual Wire IRQ...\n");
diff --git a/trunk/arch/x86/kernel/apic/nmi.c b/trunk/arch/x86/kernel/apic/nmi.c
new file mode 100644
index 000000000000..c90041ccb742
--- /dev/null
+++ b/trunk/arch/x86/kernel/apic/nmi.c
@@ -0,0 +1,567 @@
+/*
+ * NMI watchdog support on APIC systems
+ *
+ * Started by Ingo Molnar
+ *
+ * Fixes:
+ * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog.
+ * Mikael Pettersson : Power Management for local APIC NMI watchdog.
+ * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog.
+ * Pavel Machek and
+ * Mikael Pettersson : PM converted to driver model. Disable/enable API.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+int unknown_nmi_panic;
+int nmi_watchdog_enabled;
+
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
+/* nmi_active:
+ * >0: the lapic NMI watchdog is active, but can be disabled
+ * <0: the lapic NMI watchdog has not been set up, and cannot
+ * be enabled
+ * 0: the lapic NMI watchdog is disabled, but can be enabled
+ */
+atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+EXPORT_SYMBOL(nmi_active);
+
+unsigned int nmi_watchdog = NMI_NONE;
+EXPORT_SYMBOL(nmi_watchdog);
+
+static int panic_on_timeout;
+
+static unsigned int nmi_hz = HZ;
+static DEFINE_PER_CPU(short, wd_enabled);
+static int endflag __initdata;
+
+static inline unsigned int get_nmi_count(int cpu)
+{
+ return per_cpu(irq_stat, cpu).__nmi_count;
+}
+
+static inline int mce_in_progress(void)
+{
+#if defined(CONFIG_X86_MCE)
+ return atomic_read(&mce_entry) > 0;
+#endif
+ return 0;
+}
+
+/*
+ * Take the local apic timer and PIT/HPET into account. We don't
+ * know which one is active, when we have highres/dyntick on
+ */
+static inline unsigned int get_timer_irqs(int cpu)
+{
+ return per_cpu(irq_stat, cpu).apic_timer_irqs +
+ per_cpu(irq_stat, cpu).irq0_irqs;
+}
+
+#ifdef CONFIG_SMP
+/*
+ * The performance counters used by NMI_LOCAL_APIC don't trigger when
+ * the CPU is idle. To make sure the NMI watchdog really ticks on all
+ * CPUs during the test make them busy.
+ */
+static __init void nmi_cpu_busy(void *data)
+{
+ local_irq_enable_in_hardirq();
+ /*
+ * Intentionally don't use cpu_relax here. This is
+ * to make sure that the performance counter really ticks,
+ * even if there is a simulator or similar that catches the
+ * pause instruction. On a real HT machine this is fine because
+ * all other CPUs are busy with "useless" delay loops and don't
+ * care if they get somewhat less cycles.
+ */
+ while (endflag == 0)
+ mb();
+}
+#endif
+
+static void report_broken_nmi(int cpu, unsigned int *prev_nmi_count)
+{
+ printk(KERN_CONT "\n");
+
+ printk(KERN_WARNING
+ "WARNING: CPU#%d: NMI appears to be stuck (%d->%d)!\n",
+ cpu, prev_nmi_count[cpu], get_nmi_count(cpu));
+
+ printk(KERN_WARNING
+ "Please report this to bugzilla.kernel.org,\n");
+ printk(KERN_WARNING
+ "and attach the output of the 'dmesg' command.\n");
+
+ per_cpu(wd_enabled, cpu) = 0;
+ atomic_dec(&nmi_active);
+}
+
+static void __acpi_nmi_disable(void *__unused)
+{
+ apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
+}
+
+int __init check_nmi_watchdog(void)
+{
+ unsigned int *prev_nmi_count;
+ int cpu;
+
+ if (!nmi_watchdog_active() || !atomic_read(&nmi_active))
+ return 0;
+
+ prev_nmi_count = kmalloc(nr_cpu_ids * sizeof(int), GFP_KERNEL);
+ if (!prev_nmi_count)
+ goto error;
+
+ printk(KERN_INFO "Testing NMI watchdog ... ");
+
+#ifdef CONFIG_SMP
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ smp_call_function(nmi_cpu_busy, (void *)&endflag, 0);
+#endif
+
+ for_each_possible_cpu(cpu)
+ prev_nmi_count[cpu] = get_nmi_count(cpu);
+ local_irq_enable();
+ mdelay((20 * 1000) / nmi_hz); /* wait 20 ticks */
+
+ for_each_online_cpu(cpu) {
+ if (!per_cpu(wd_enabled, cpu))
+ continue;
+ if (get_nmi_count(cpu) - prev_nmi_count[cpu] <= 5)
+ report_broken_nmi(cpu, prev_nmi_count);
+ }
+ endflag = 1;
+ if (!atomic_read(&nmi_active)) {
+ kfree(prev_nmi_count);
+ atomic_set(&nmi_active, -1);
+ goto error;
+ }
+ printk("OK.\n");
+
+ /*
+ * now that we know it works we can reduce NMI frequency to
+ * something more reasonable; makes a difference in some configs
+ */
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ nmi_hz = lapic_adjust_nmi_hz(1);
+
+ kfree(prev_nmi_count);
+ return 0;
+error:
+ if (nmi_watchdog == NMI_IO_APIC) {
+ if (!timer_through_8259)
+ legacy_pic->mask(0);
+ on_each_cpu(__acpi_nmi_disable, NULL, 1);
+ }
+
+#ifdef CONFIG_X86_32
+ timer_ack = 0;
+#endif
+ return -1;
+}
+
+static int __init setup_nmi_watchdog(char *str)
+{
+ unsigned int nmi;
+
+ if (!strncmp(str, "panic", 5)) {
+ panic_on_timeout = 1;
+ str = strchr(str, ',');
+ if (!str)
+ return 1;
+ ++str;
+ }
+
+ if (!strncmp(str, "lapic", 5))
+ nmi_watchdog = NMI_LOCAL_APIC;
+ else if (!strncmp(str, "ioapic", 6))
+ nmi_watchdog = NMI_IO_APIC;
+ else {
+ get_option(&str, &nmi);
+ if (nmi >= NMI_INVALID)
+ return 0;
+ nmi_watchdog = nmi;
+ }
+
+ return 1;
+}
+__setup("nmi_watchdog=", setup_nmi_watchdog);
+
+/*
+ * Suspend/resume support
+ */
+#ifdef CONFIG_PM
+
+static int nmi_pm_active; /* nmi_active before suspend */
+
+static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state)
+{
+ /* only CPU0 goes here, other CPUs should be offline */
+ nmi_pm_active = atomic_read(&nmi_active);
+ stop_apic_nmi_watchdog(NULL);
+ BUG_ON(atomic_read(&nmi_active) != 0);
+ return 0;
+}
+
+static int lapic_nmi_resume(struct sys_device *dev)
+{
+ /* only CPU0 goes here, other CPUs should be offline */
+ if (nmi_pm_active > 0) {
+ setup_apic_nmi_watchdog(NULL);
+ touch_nmi_watchdog();
+ }
+ return 0;
+}
+
+static struct sysdev_class nmi_sysclass = {
+ .name = "lapic_nmi",
+ .resume = lapic_nmi_resume,
+ .suspend = lapic_nmi_suspend,
+};
+
+static struct sys_device device_lapic_nmi = {
+ .id = 0,
+ .cls = &nmi_sysclass,
+};
+
+static int __init init_lapic_nmi_sysfs(void)
+{
+ int error;
+
+ /*
+ * should really be a BUG_ON but b/c this is an
+ * init call, it just doesn't work. -dcz
+ */
+ if (nmi_watchdog != NMI_LOCAL_APIC)
+ return 0;
+
+ if (atomic_read(&nmi_active) < 0)
+ return 0;
+
+ error = sysdev_class_register(&nmi_sysclass);
+ if (!error)
+ error = sysdev_register(&device_lapic_nmi);
+ return error;
+}
+
+/* must come after the local APIC's device_initcall() */
+late_initcall(init_lapic_nmi_sysfs);
+
+#endif /* CONFIG_PM */
+
+static void __acpi_nmi_enable(void *__unused)
+{
+ apic_write(APIC_LVT0, APIC_DM_NMI);
+}
+
+/*
+ * Enable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_enable(void)
+{
+ if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+ on_each_cpu(__acpi_nmi_enable, NULL, 1);
+}
+
+/*
+ * Disable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_disable(void)
+{
+ if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+ on_each_cpu(__acpi_nmi_disable, NULL, 1);
+}
+
+/*
+ * This function is called as soon the LAPIC NMI watchdog driver has everything
+ * in place and it's ready to check if the NMIs belong to the NMI watchdog
+ */
+void cpu_nmi_set_wd_enabled(void)
+{
+ __get_cpu_var(wd_enabled) = 1;
+}
+
+void setup_apic_nmi_watchdog(void *unused)
+{
+ if (__get_cpu_var(wd_enabled))
+ return;
+
+ /* cheap hack to support suspend/resume */
+ /* if cpu0 is not active neither should the other cpus */
+ if (smp_processor_id() != 0 && atomic_read(&nmi_active) <= 0)
+ return;
+
+ switch (nmi_watchdog) {
+ case NMI_LOCAL_APIC:
+ if (lapic_watchdog_init(nmi_hz) < 0) {
+ __get_cpu_var(wd_enabled) = 0;
+ return;
+ }
+ /* FALL THROUGH */
+ case NMI_IO_APIC:
+ __get_cpu_var(wd_enabled) = 1;
+ atomic_inc(&nmi_active);
+ }
+}
+
+void stop_apic_nmi_watchdog(void *unused)
+{
+ /* only support LOCAL and IO APICs for now */
+ if (!nmi_watchdog_active())
+ return;
+ if (__get_cpu_var(wd_enabled) == 0)
+ return;
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ lapic_watchdog_stop();
+ else
+ __acpi_nmi_disable(NULL);
+ __get_cpu_var(wd_enabled) = 0;
+ atomic_dec(&nmi_active);
+}
+
+/*
+ * the best way to detect whether a CPU has a 'hard lockup' problem
+ * is to check it's local APIC timer IRQ counts. If they are not
+ * changing then that CPU has some problem.
+ *
+ * as these watchdog NMI IRQs are generated on every CPU, we only
+ * have to check the current processor.
+ *
+ * since NMIs don't listen to _any_ locks, we have to be extremely
+ * careful not to rely on unsafe variables. The printk might lock
+ * up though, so we have to break up any console locks first ...
+ * [when there will be more tty-related locks, break them up here too!]
+ */
+
+static DEFINE_PER_CPU(unsigned, last_irq_sum);
+static DEFINE_PER_CPU(long, alert_counter);
+static DEFINE_PER_CPU(int, nmi_touch);
+
+void touch_nmi_watchdog(void)
+{
+ if (nmi_watchdog_active()) {
+ unsigned cpu;
+
+ /*
+ * Tell other CPUs to reset their alert counters. We cannot
+ * do it ourselves because the alert count increase is not
+ * atomic.
+ */
+ for_each_present_cpu(cpu) {
+ if (per_cpu(nmi_touch, cpu) != 1)
+ per_cpu(nmi_touch, cpu) = 1;
+ }
+ }
+
+ /*
+ * Tickle the softlockup detector too:
+ */
+ touch_softlockup_watchdog();
+}
+EXPORT_SYMBOL(touch_nmi_watchdog);
+
+notrace __kprobes int
+nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
+{
+ /*
+ * Since current_thread_info()-> is always on the stack, and we
+ * always switch the stack NMI-atomically, it's safe to use
+ * smp_processor_id().
+ */
+ unsigned int sum;
+ int touched = 0;
+ int cpu = smp_processor_id();
+ int rc = 0;
+
+ sum = get_timer_irqs(cpu);
+
+ if (__get_cpu_var(nmi_touch)) {
+ __get_cpu_var(nmi_touch) = 0;
+ touched = 1;
+ }
+
+ /* We can be called before check_nmi_watchdog, hence NULL check. */
+ if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+ static DEFINE_RAW_SPINLOCK(lock); /* Serialise the printks */
+
+ raw_spin_lock(&lock);
+ printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
+ show_regs(regs);
+ dump_stack();
+ raw_spin_unlock(&lock);
+ cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+
+ rc = 1;
+ }
+
+ /* Could check oops_in_progress here too, but it's safer not to */
+ if (mce_in_progress())
+ touched = 1;
+
+ /* if the none of the timers isn't firing, this cpu isn't doing much */
+ if (!touched && __get_cpu_var(last_irq_sum) == sum) {
+ /*
+ * Ayiee, looks like this CPU is stuck ...
+ * wait a few IRQs (5 seconds) before doing the oops ...
+ */
+ __this_cpu_inc(alert_counter);
+ if (__this_cpu_read(alert_counter) == 5 * nmi_hz)
+ /*
+ * die_nmi will return ONLY if NOTIFY_STOP happens..
+ */
+ die_nmi("BUG: NMI Watchdog detected LOCKUP",
+ regs, panic_on_timeout);
+ } else {
+ __get_cpu_var(last_irq_sum) = sum;
+ __this_cpu_write(alert_counter, 0);
+ }
+
+ /* see if the nmi watchdog went off */
+ if (!__get_cpu_var(wd_enabled))
+ return rc;
+ switch (nmi_watchdog) {
+ case NMI_LOCAL_APIC:
+ rc |= lapic_wd_event(nmi_hz);
+ break;
+ case NMI_IO_APIC:
+ /*
+ * don't know how to accurately check for this.
+ * just assume it was a watchdog timer interrupt
+ * This matches the old behaviour.
+ */
+ rc = 1;
+ break;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_SYSCTL
+
+static void enable_ioapic_nmi_watchdog_single(void *unused)
+{
+ __get_cpu_var(wd_enabled) = 1;
+ atomic_inc(&nmi_active);
+ __acpi_nmi_enable(NULL);
+}
+
+static void enable_ioapic_nmi_watchdog(void)
+{
+ on_each_cpu(enable_ioapic_nmi_watchdog_single, NULL, 1);
+ touch_nmi_watchdog();
+}
+
+static void disable_ioapic_nmi_watchdog(void)
+{
+ on_each_cpu(stop_apic_nmi_watchdog, NULL, 1);
+}
+
+static int __init setup_unknown_nmi_panic(char *str)
+{
+ unknown_nmi_panic = 1;
+ return 1;
+}
+__setup("unknown_nmi_panic", setup_unknown_nmi_panic);
+
+static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
+{
+ unsigned char reason = get_nmi_reason();
+ char buf[64];
+
+ sprintf(buf, "NMI received for unknown reason %02x\n", reason);
+ die_nmi(buf, regs, 1); /* Always panic here */
+ return 0;
+}
+
+/*
+ * proc handler for /proc/sys/kernel/nmi
+ */
+int proc_nmi_enabled(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ int old_state;
+
+ nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
+ old_state = nmi_watchdog_enabled;
+ proc_dointvec(table, write, buffer, length, ppos);
+ if (!!old_state == !!nmi_watchdog_enabled)
+ return 0;
+
+ if (atomic_read(&nmi_active) < 0 || !nmi_watchdog_active()) {
+ printk(KERN_WARNING
+ "NMI watchdog is permanently disabled\n");
+ return -EIO;
+ }
+
+ if (nmi_watchdog == NMI_LOCAL_APIC) {
+ if (nmi_watchdog_enabled)
+ enable_lapic_nmi_watchdog();
+ else
+ disable_lapic_nmi_watchdog();
+ } else if (nmi_watchdog == NMI_IO_APIC) {
+ if (nmi_watchdog_enabled)
+ enable_ioapic_nmi_watchdog();
+ else
+ disable_ioapic_nmi_watchdog();
+ } else {
+ printk(KERN_WARNING
+ "NMI watchdog doesn't know what hardware to touch\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_SYSCTL */
+
+int do_nmi_callback(struct pt_regs *regs, int cpu)
+{
+#ifdef CONFIG_SYSCTL
+ if (unknown_nmi_panic)
+ return unknown_nmi_panic_callback(regs, cpu);
+#endif
+ return 0;
+}
+
+void arch_trigger_all_cpu_backtrace(void)
+{
+ int i;
+
+ cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+
+ printk(KERN_INFO "sending NMI to all CPUs:\n");
+ apic->send_IPI_all(NMI_VECTOR);
+
+ /* Wait for up to 10 seconds for all CPUs to do the backtrace */
+ for (i = 0; i < 10 * 1000; i++) {
+ if (cpumask_empty(to_cpumask(backtrace_mask)))
+ break;
+ mdelay(1);
+ }
+}
diff --git a/trunk/arch/x86/kernel/cpu/common.c b/trunk/arch/x86/kernel/cpu/common.c
index 1d59834396bd..4b68bda30938 100644
--- a/trunk/arch/x86/kernel/cpu/common.c
+++ b/trunk/arch/x86/kernel/cpu/common.c
@@ -894,6 +894,7 @@ void __init identify_boot_cpu(void)
#else
vgetcpu_set_mode();
#endif
+ init_hw_perf_events();
}
void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
diff --git a/trunk/arch/x86/kernel/cpu/perf_event.c b/trunk/arch/x86/kernel/cpu/perf_event.c
index 817d2b195e8e..ed6310183efb 100644
--- a/trunk/arch/x86/kernel/cpu/perf_event.c
+++ b/trunk/arch/x86/kernel/cpu/perf_event.c
@@ -330,6 +330,9 @@ static bool reserve_pmc_hardware(void)
{
int i;
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ disable_lapic_nmi_watchdog();
+
for (i = 0; i < x86_pmu.num_counters; i++) {
if (!reserve_perfctr_nmi(x86_pmu.perfctr + i))
goto perfctr_fail;
@@ -352,6 +355,9 @@ static bool reserve_pmc_hardware(void)
for (i--; i >= 0; i--)
release_perfctr_nmi(x86_pmu.perfctr + i);
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ enable_lapic_nmi_watchdog();
+
return false;
}
@@ -363,6 +369,9 @@ static void release_pmc_hardware(void)
release_perfctr_nmi(x86_pmu.perfctr + i);
release_evntsel_nmi(x86_pmu.eventsel + i);
}
+
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ enable_lapic_nmi_watchdog();
}
#else
@@ -372,20 +381,6 @@ static void release_pmc_hardware(void) {}
#endif
-static bool check_hw_exists(void)
-{
- u64 val, val_new = 0;
- int ret = 0;
-
- val = 0xabcdUL;
- ret |= checking_wrmsrl(x86_pmu.perfctr, val);
- ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new);
- if (ret || val != val_new)
- return false;
-
- return true;
-}
-
static void reserve_ds_buffers(void);
static void release_ds_buffers(void);
@@ -442,7 +437,7 @@ static int x86_setup_perfctr(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw;
u64 config;
- if (!is_sampling_event(event)) {
+ if (!hwc->sample_period) {
hwc->sample_period = x86_pmu.max_period;
hwc->last_period = hwc->sample_period;
local64_set(&hwc->period_left, hwc->sample_period);
@@ -1353,7 +1348,7 @@ static void __init pmu_check_apic(void)
pr_info("no hardware sampling interrupt available.\n");
}
-int __init init_hw_perf_events(void)
+void __init init_hw_perf_events(void)
{
struct event_constraint *c;
int err;
@@ -1368,21 +1363,15 @@ int __init init_hw_perf_events(void)
err = amd_pmu_init();
break;
default:
- return 0;
+ return;
}
if (err != 0) {
pr_cont("no PMU driver, software events only.\n");
- return 0;
+ return;
}
pmu_check_apic();
- /* sanity check that the hardware exists or is emulated */
- if (!check_hw_exists()) {
- pr_cont("Broken PMU hardware detected, software events only.\n");
- return 0;
- }
-
pr_cont("%s PMU driver.\n", x86_pmu.name);
if (x86_pmu.quirks)
@@ -1431,10 +1420,7 @@ int __init init_hw_perf_events(void)
perf_pmu_register(&pmu);
perf_cpu_notifier(x86_pmu_notifier);
-
- return 0;
}
-early_initcall(init_hw_perf_events);
static inline void x86_pmu_read(struct perf_event *event)
{
@@ -1680,7 +1666,7 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
perf_callchain_store(entry, regs->ip);
- dump_trace(NULL, regs, NULL, &backtrace_ops, entry);
+ dump_trace(NULL, regs, NULL, regs->bp, &backtrace_ops, entry);
}
#ifdef CONFIG_COMPAT
diff --git a/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c b/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c
index 14d45928c282..d9f4ff8fcd69 100644
--- a/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c
+++ b/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c
@@ -22,6 +22,26 @@
#include
#include
+struct nmi_watchdog_ctlblk {
+ unsigned int cccr_msr;
+ unsigned int perfctr_msr; /* the MSR to reset in NMI handler */
+ unsigned int evntsel_msr; /* the MSR to select the events to handle */
+};
+
+/* Interface defining a CPU specific perfctr watchdog */
+struct wd_ops {
+ int (*reserve)(void);
+ void (*unreserve)(void);
+ int (*setup)(unsigned nmi_hz);
+ void (*rearm)(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz);
+ void (*stop)(void);
+ unsigned perfctr;
+ unsigned evntsel;
+ u64 checkbit;
+};
+
+static const struct wd_ops *wd_ops;
+
/*
* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
* offset from MSR_P4_BSU_ESCR0.
@@ -40,6 +60,8 @@
static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);
static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);
+static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+
/* converts an msr to an appropriate reservation bit */
static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
{
@@ -150,3 +172,623 @@ void release_evntsel_nmi(unsigned int msr)
clear_bit(counter, evntsel_nmi_owner);
}
EXPORT_SYMBOL(release_evntsel_nmi);
+
+void disable_lapic_nmi_watchdog(void)
+{
+ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+ if (atomic_read(&nmi_active) <= 0)
+ return;
+
+ on_each_cpu(stop_apic_nmi_watchdog, NULL, 1);
+
+ if (wd_ops)
+ wd_ops->unreserve();
+
+ BUG_ON(atomic_read(&nmi_active) != 0);
+}
+
+void enable_lapic_nmi_watchdog(void)
+{
+ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+ /* are we already enabled */
+ if (atomic_read(&nmi_active) != 0)
+ return;
+
+ /* are we lapic aware */
+ if (!wd_ops)
+ return;
+ if (!wd_ops->reserve()) {
+ printk(KERN_ERR "NMI watchdog: cannot reserve perfctrs\n");
+ return;
+ }
+
+ on_each_cpu(setup_apic_nmi_watchdog, NULL, 1);
+ touch_nmi_watchdog();
+}
+
+/*
+ * Activate the NMI watchdog via the local APIC.
+ */
+
+static unsigned int adjust_for_32bit_ctr(unsigned int hz)
+{
+ u64 counter_val;
+ unsigned int retval = hz;
+
+ /*
+ * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter
+ * are writable, with higher bits sign extending from bit 31.
+ * So, we can only program the counter with 31 bit values and
+ * 32nd bit should be 1, for 33.. to be 1.
+ * Find the appropriate nmi_hz
+ */
+ counter_val = (u64)cpu_khz * 1000;
+ do_div(counter_val, retval);
+ if (counter_val > 0x7fffffffULL) {
+ u64 count = (u64)cpu_khz * 1000;
+ do_div(count, 0x7fffffffUL);
+ retval = count + 1;
+ }
+ return retval;
+}
+
+static void write_watchdog_counter(unsigned int perfctr_msr,
+ const char *descr, unsigned nmi_hz)
+{
+ u64 count = (u64)cpu_khz * 1000;
+
+ do_div(count, nmi_hz);
+ if (descr)
+ pr_debug("setting %s to -0x%08Lx\n", descr, count);
+ wrmsrl(perfctr_msr, 0 - count);
+}
+
+static void write_watchdog_counter32(unsigned int perfctr_msr,
+ const char *descr, unsigned nmi_hz)
+{
+ u64 count = (u64)cpu_khz * 1000;
+
+ do_div(count, nmi_hz);
+ if (descr)
+ pr_debug("setting %s to -0x%08Lx\n", descr, count);
+ wrmsr(perfctr_msr, (u32)(-count), 0);
+}
+
+/*
+ * AMD K7/K8/Family10h/Family11h support.
+ * AMD keeps this interface nicely stable so there is not much variety
+ */
+#define K7_EVNTSEL_ENABLE (1 << 22)
+#define K7_EVNTSEL_INT (1 << 20)
+#define K7_EVNTSEL_OS (1 << 17)
+#define K7_EVNTSEL_USR (1 << 16)
+#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
+#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
+
+static int setup_k7_watchdog(unsigned nmi_hz)
+{
+ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ perfctr_msr = wd_ops->perfctr;
+ evntsel_msr = wd_ops->evntsel;
+
+ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = K7_EVNTSEL_INT
+ | K7_EVNTSEL_OS
+ | K7_EVNTSEL_USR
+ | K7_NMI_EVENT;
+
+ /* setup the timer */
+ wrmsr(evntsel_msr, evntsel, 0);
+ write_watchdog_counter(perfctr_msr, "K7_PERFCTR0", nmi_hz);
+
+ /* initialize the wd struct before enabling */
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = 0; /* unused */
+
+ /* ok, everything is initialized, announce that we're set */
+ cpu_nmi_set_wd_enabled();
+
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= K7_EVNTSEL_ENABLE;
+ wrmsr(evntsel_msr, evntsel, 0);
+
+ return 1;
+}
+
+static void single_msr_stop_watchdog(void)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ wrmsr(wd->evntsel_msr, 0, 0);
+}
+
+static int single_msr_reserve(void)
+{
+ if (!reserve_perfctr_nmi(wd_ops->perfctr))
+ return 0;
+
+ if (!reserve_evntsel_nmi(wd_ops->evntsel)) {
+ release_perfctr_nmi(wd_ops->perfctr);
+ return 0;
+ }
+ return 1;
+}
+
+static void single_msr_unreserve(void)
+{
+ release_evntsel_nmi(wd_ops->evntsel);
+ release_perfctr_nmi(wd_ops->perfctr);
+}
+
+static void __kprobes
+single_msr_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+ /* start the cycle over again */
+ write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static const struct wd_ops k7_wd_ops = {
+ .reserve = single_msr_reserve,
+ .unreserve = single_msr_unreserve,
+ .setup = setup_k7_watchdog,
+ .rearm = single_msr_rearm,
+ .stop = single_msr_stop_watchdog,
+ .perfctr = MSR_K7_PERFCTR0,
+ .evntsel = MSR_K7_EVNTSEL0,
+ .checkbit = 1ULL << 47,
+};
+
+/*
+ * Intel Model 6 (PPro+,P2,P3,P-M,Core1)
+ */
+#define P6_EVNTSEL0_ENABLE (1 << 22)
+#define P6_EVNTSEL_INT (1 << 20)
+#define P6_EVNTSEL_OS (1 << 17)
+#define P6_EVNTSEL_USR (1 << 16)
+#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
+#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
+
+static int setup_p6_watchdog(unsigned nmi_hz)
+{
+ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ perfctr_msr = wd_ops->perfctr;
+ evntsel_msr = wd_ops->evntsel;
+
+ /* KVM doesn't implement this MSR */
+ if (wrmsr_safe(perfctr_msr, 0, 0) < 0)
+ return 0;
+
+ evntsel = P6_EVNTSEL_INT
+ | P6_EVNTSEL_OS
+ | P6_EVNTSEL_USR
+ | P6_NMI_EVENT;
+
+ /* setup the timer */
+ wrmsr(evntsel_msr, evntsel, 0);
+ nmi_hz = adjust_for_32bit_ctr(nmi_hz);
+ write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0", nmi_hz);
+
+ /* initialize the wd struct before enabling */
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = 0; /* unused */
+
+ /* ok, everything is initialized, announce that we're set */
+ cpu_nmi_set_wd_enabled();
+
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= P6_EVNTSEL0_ENABLE;
+ wrmsr(evntsel_msr, evntsel, 0);
+
+ return 1;
+}
+
+static void __kprobes p6_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+ /*
+ * P6 based Pentium M need to re-unmask
+ * the apic vector but it doesn't hurt
+ * other P6 variant.
+ * ArchPerfom/Core Duo also needs this
+ */
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+
+ /* P6/ARCH_PERFMON has 32 bit counter write */
+ write_watchdog_counter32(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static const struct wd_ops p6_wd_ops = {
+ .reserve = single_msr_reserve,
+ .unreserve = single_msr_unreserve,
+ .setup = setup_p6_watchdog,
+ .rearm = p6_rearm,
+ .stop = single_msr_stop_watchdog,
+ .perfctr = MSR_P6_PERFCTR0,
+ .evntsel = MSR_P6_EVNTSEL0,
+ .checkbit = 1ULL << 39,
+};
+
+/*
+ * Intel P4 performance counters.
+ * By far the most complicated of all.
+ */
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1 << 7)
+#define P4_ESCR_EVENT_SELECT(N) ((N) << 25)
+#define P4_ESCR_OS (1 << 3)
+#define P4_ESCR_USR (1 << 2)
+#define P4_CCCR_OVF_PMI0 (1 << 26)
+#define P4_CCCR_OVF_PMI1 (1 << 27)
+#define P4_CCCR_THRESHOLD(N) ((N) << 20)
+#define P4_CCCR_COMPLEMENT (1 << 19)
+#define P4_CCCR_COMPARE (1 << 18)
+#define P4_CCCR_REQUIRED (3 << 16)
+#define P4_CCCR_ESCR_SELECT(N) ((N) << 13)
+#define P4_CCCR_ENABLE (1 << 12)
+#define P4_CCCR_OVF (1 << 31)
+
+#define P4_CONTROLS 18
+static unsigned int p4_controls[18] = {
+ MSR_P4_BPU_CCCR0,
+ MSR_P4_BPU_CCCR1,
+ MSR_P4_BPU_CCCR2,
+ MSR_P4_BPU_CCCR3,
+ MSR_P4_MS_CCCR0,
+ MSR_P4_MS_CCCR1,
+ MSR_P4_MS_CCCR2,
+ MSR_P4_MS_CCCR3,
+ MSR_P4_FLAME_CCCR0,
+ MSR_P4_FLAME_CCCR1,
+ MSR_P4_FLAME_CCCR2,
+ MSR_P4_FLAME_CCCR3,
+ MSR_P4_IQ_CCCR0,
+ MSR_P4_IQ_CCCR1,
+ MSR_P4_IQ_CCCR2,
+ MSR_P4_IQ_CCCR3,
+ MSR_P4_IQ_CCCR4,
+ MSR_P4_IQ_CCCR5,
+};
+/*
+ * Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+ * CRU_ESCR0 (with any non-null event selector) through a complemented
+ * max threshold. [IA32-Vol3, Section 14.9.9]
+ */
+static int setup_p4_watchdog(unsigned nmi_hz)
+{
+ unsigned int perfctr_msr, evntsel_msr, cccr_msr;
+ unsigned int evntsel, cccr_val;
+ unsigned int misc_enable, dummy;
+ unsigned int ht_num;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
+ if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+ return 0;
+
+#ifdef CONFIG_SMP
+ /* detect which hyperthread we are on */
+ if (smp_num_siblings == 2) {
+ unsigned int ebx, apicid;
+
+ ebx = cpuid_ebx(1);
+ apicid = (ebx >> 24) & 0xff;
+ ht_num = apicid & 1;
+ } else
+#endif
+ ht_num = 0;
+
+ /*
+ * performance counters are shared resources
+ * assign each hyperthread its own set
+ * (re-use the ESCR0 register, seems safe
+ * and keeps the cccr_val the same)
+ */
+ if (!ht_num) {
+ /* logical cpu 0 */
+ perfctr_msr = MSR_P4_IQ_PERFCTR0;
+ evntsel_msr = MSR_P4_CRU_ESCR0;
+ cccr_msr = MSR_P4_IQ_CCCR0;
+ cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
+
+ /*
+ * If we're on the kdump kernel or other situation, we may
+ * still have other performance counter registers set to
+ * interrupt and they'll keep interrupting forever because
+ * of the P4_CCCR_OVF quirk. So we need to ACK all the
+ * pending interrupts and disable all the registers here,
+ * before reenabling the NMI delivery. Refer to p4_rearm()
+ * about the P4_CCCR_OVF quirk.
+ */
+ if (reset_devices) {
+ unsigned int low, high;
+ int i;
+
+ for (i = 0; i < P4_CONTROLS; i++) {
+ rdmsr(p4_controls[i], low, high);
+ low &= ~(P4_CCCR_ENABLE | P4_CCCR_OVF);
+ wrmsr(p4_controls[i], low, high);
+ }
+ }
+ } else {
+ /* logical cpu 1 */
+ perfctr_msr = MSR_P4_IQ_PERFCTR1;
+ evntsel_msr = MSR_P4_CRU_ESCR0;
+ cccr_msr = MSR_P4_IQ_CCCR1;
+
+ /* Pentium 4 D processors don't support P4_CCCR_OVF_PMI1 */
+ if (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask == 4)
+ cccr_val = P4_CCCR_OVF_PMI0;
+ else
+ cccr_val = P4_CCCR_OVF_PMI1;
+ cccr_val |= P4_CCCR_ESCR_SELECT(4);
+ }
+
+ evntsel = P4_ESCR_EVENT_SELECT(0x3F)
+ | P4_ESCR_OS
+ | P4_ESCR_USR;
+
+ cccr_val |= P4_CCCR_THRESHOLD(15)
+ | P4_CCCR_COMPLEMENT
+ | P4_CCCR_COMPARE
+ | P4_CCCR_REQUIRED;
+
+ wrmsr(evntsel_msr, evntsel, 0);
+ wrmsr(cccr_msr, cccr_val, 0);
+ write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0", nmi_hz);
+
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = cccr_msr;
+
+ /* ok, everything is initialized, announce that we're set */
+ cpu_nmi_set_wd_enabled();
+
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ cccr_val |= P4_CCCR_ENABLE;
+ wrmsr(cccr_msr, cccr_val, 0);
+ return 1;
+}
+
+static void stop_p4_watchdog(void)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+ wrmsr(wd->cccr_msr, 0, 0);
+ wrmsr(wd->evntsel_msr, 0, 0);
+}
+
+static int p4_reserve(void)
+{
+ if (!reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR0))
+ return 0;
+#ifdef CONFIG_SMP
+ if (smp_num_siblings > 1 && !reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR1))
+ goto fail1;
+#endif
+ if (!reserve_evntsel_nmi(MSR_P4_CRU_ESCR0))
+ goto fail2;
+ /* RED-PEN why is ESCR1 not reserved here? */
+ return 1;
+ fail2:
+#ifdef CONFIG_SMP
+ if (smp_num_siblings > 1)
+ release_perfctr_nmi(MSR_P4_IQ_PERFCTR1);
+ fail1:
+#endif
+ release_perfctr_nmi(MSR_P4_IQ_PERFCTR0);
+ return 0;
+}
+
+static void p4_unreserve(void)
+{
+#ifdef CONFIG_SMP
+ if (smp_num_siblings > 1)
+ release_perfctr_nmi(MSR_P4_IQ_PERFCTR1);
+#endif
+ release_evntsel_nmi(MSR_P4_CRU_ESCR0);
+ release_perfctr_nmi(MSR_P4_IQ_PERFCTR0);
+}
+
+static void __kprobes p4_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+ unsigned dummy;
+ /*
+ * P4 quirks:
+ * - An overflown perfctr will assert its interrupt
+ * until the OVF flag in its CCCR is cleared.
+ * - LVTPC is masked on interrupt and must be
+ * unmasked by the LVTPC handler.
+ */
+ rdmsrl(wd->cccr_msr, dummy);
+ dummy &= ~P4_CCCR_OVF;
+ wrmsrl(wd->cccr_msr, dummy);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ /* start the cycle over again */
+ write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static const struct wd_ops p4_wd_ops = {
+ .reserve = p4_reserve,
+ .unreserve = p4_unreserve,
+ .setup = setup_p4_watchdog,
+ .rearm = p4_rearm,
+ .stop = stop_p4_watchdog,
+ /* RED-PEN this is wrong for the other sibling */
+ .perfctr = MSR_P4_BPU_PERFCTR0,
+ .evntsel = MSR_P4_BSU_ESCR0,
+ .checkbit = 1ULL << 39,
+};
+
+/*
+ * Watchdog using the Intel architected PerfMon.
+ * Used for Core2 and hopefully all future Intel CPUs.
+ */
+#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
+#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
+
+static struct wd_ops intel_arch_wd_ops;
+
+static int setup_intel_arch_watchdog(unsigned nmi_hz)
+{
+ unsigned int ebx;
+ union cpuid10_eax eax;
+ unsigned int unused;
+ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ /*
+ * Check whether the Architectural PerfMon supports
+ * Unhalted Core Cycles Event or not.
+ * NOTE: Corresponding bit = 0 in ebx indicates event present.
+ */
+ cpuid(10, &(eax.full), &ebx, &unused, &unused);
+ if ((eax.split.mask_length <
+ (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
+ (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+ return 0;
+
+ perfctr_msr = wd_ops->perfctr;
+ evntsel_msr = wd_ops->evntsel;
+
+ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = ARCH_PERFMON_EVENTSEL_INT
+ | ARCH_PERFMON_EVENTSEL_OS
+ | ARCH_PERFMON_EVENTSEL_USR
+ | ARCH_PERFMON_NMI_EVENT_SEL
+ | ARCH_PERFMON_NMI_EVENT_UMASK;
+
+ /* setup the timer */
+ wrmsr(evntsel_msr, evntsel, 0);
+ nmi_hz = adjust_for_32bit_ctr(nmi_hz);
+ write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz);
+
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = 0; /* unused */
+
+ /* ok, everything is initialized, announce that we're set */
+ cpu_nmi_set_wd_enabled();
+
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= ARCH_PERFMON_EVENTSEL_ENABLE;
+ wrmsr(evntsel_msr, evntsel, 0);
+ intel_arch_wd_ops.checkbit = 1ULL << (eax.split.bit_width - 1);
+ return 1;
+}
+
+static struct wd_ops intel_arch_wd_ops __read_mostly = {
+ .reserve = single_msr_reserve,
+ .unreserve = single_msr_unreserve,
+ .setup = setup_intel_arch_watchdog,
+ .rearm = p6_rearm,
+ .stop = single_msr_stop_watchdog,
+ .perfctr = MSR_ARCH_PERFMON_PERFCTR1,
+ .evntsel = MSR_ARCH_PERFMON_EVENTSEL1,
+};
+
+static void probe_nmi_watchdog(void)
+{
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ if (boot_cpu_data.x86 == 6 ||
+ (boot_cpu_data.x86 >= 0xf && boot_cpu_data.x86 <= 0x15))
+ wd_ops = &k7_wd_ops;
+ return;
+ case X86_VENDOR_INTEL:
+ /* Work around where perfctr1 doesn't have a working enable
+ * bit as described in the following errata:
+ * AE49 Core Duo and Intel Core Solo 65 nm
+ * AN49 Intel Pentium Dual-Core
+ * AF49 Dual-Core Intel Xeon Processor LV
+ */
+ if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 14) ||
+ ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 15 &&
+ boot_cpu_data.x86_mask == 4))) {
+ intel_arch_wd_ops.perfctr = MSR_ARCH_PERFMON_PERFCTR0;
+ intel_arch_wd_ops.evntsel = MSR_ARCH_PERFMON_EVENTSEL0;
+ }
+ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+ wd_ops = &intel_arch_wd_ops;
+ break;
+ }
+ switch (boot_cpu_data.x86) {
+ case 6:
+ if (boot_cpu_data.x86_model > 13)
+ return;
+
+ wd_ops = &p6_wd_ops;
+ break;
+ case 15:
+ wd_ops = &p4_wd_ops;
+ break;
+ default:
+ return;
+ }
+ break;
+ }
+}
+
+/* Interface to nmi.c */
+
+int lapic_watchdog_init(unsigned nmi_hz)
+{
+ if (!wd_ops) {
+ probe_nmi_watchdog();
+ if (!wd_ops) {
+ printk(KERN_INFO "NMI watchdog: CPU not supported\n");
+ return -1;
+ }
+
+ if (!wd_ops->reserve()) {
+ printk(KERN_ERR
+ "NMI watchdog: cannot reserve perfctrs\n");
+ return -1;
+ }
+ }
+
+ if (!(wd_ops->setup(nmi_hz))) {
+ printk(KERN_ERR "Cannot setup NMI watchdog on CPU %d\n",
+ raw_smp_processor_id());
+ return -1;
+ }
+
+ return 0;
+}
+
+void lapic_watchdog_stop(void)
+{
+ if (wd_ops)
+ wd_ops->stop();
+}
+
+unsigned lapic_adjust_nmi_hz(unsigned hz)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+ if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
+ wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR1)
+ hz = adjust_for_32bit_ctr(hz);
+ return hz;
+}
+
+int __kprobes lapic_wd_event(unsigned nmi_hz)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+ u64 ctr;
+
+ rdmsrl(wd->perfctr_msr, ctr);
+ if (ctr & wd_ops->checkbit) /* perfctr still running? */
+ return 0;
+
+ wd_ops->rearm(wd, nmi_hz);
+ return 1;
+}
diff --git a/trunk/arch/x86/kernel/cpuid.c b/trunk/arch/x86/kernel/cpuid.c
index 212a6a42527c..1b7b31ab7d86 100644
--- a/trunk/arch/x86/kernel/cpuid.c
+++ b/trunk/arch/x86/kernel/cpuid.c
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/x86/kernel/dumpstack.c b/trunk/arch/x86/kernel/dumpstack.c
index 8474c998cbd4..6e8752c1bd52 100644
--- a/trunk/arch/x86/kernel/dumpstack.c
+++ b/trunk/arch/x86/kernel/dumpstack.c
@@ -175,21 +175,21 @@ static const struct stacktrace_ops print_trace_ops = {
void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack, char *log_lvl)
+ unsigned long *stack, unsigned long bp, char *log_lvl)
{
printk("%sCall Trace:\n", log_lvl);
- dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
+ dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
}
void show_trace(struct task_struct *task, struct pt_regs *regs,
- unsigned long *stack)
+ unsigned long *stack, unsigned long bp)
{
- show_trace_log_lvl(task, regs, stack, "");
+ show_trace_log_lvl(task, regs, stack, bp, "");
}
void show_stack(struct task_struct *task, unsigned long *sp)
{
- show_stack_log_lvl(task, NULL, sp, "");
+ show_stack_log_lvl(task, NULL, sp, 0, "");
}
/*
@@ -210,7 +210,7 @@ void dump_stack(void)
init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
- show_trace(NULL, NULL, &stack);
+ show_trace(NULL, NULL, &stack, bp);
}
EXPORT_SYMBOL(dump_stack);
diff --git a/trunk/arch/x86/kernel/dumpstack_32.c b/trunk/arch/x86/kernel/dumpstack_32.c
index 74cc1eda384b..1bc7f75a5bda 100644
--- a/trunk/arch/x86/kernel/dumpstack_32.c
+++ b/trunk/arch/x86/kernel/dumpstack_32.c
@@ -17,12 +17,11 @@
#include
-void dump_trace(struct task_struct *task,
- struct pt_regs *regs, unsigned long *stack,
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data)
{
int graph = 0;
- unsigned long bp;
if (!task)
task = current;
@@ -35,7 +34,18 @@ void dump_trace(struct task_struct *task,
stack = (unsigned long *)task->thread.sp;
}
- bp = stack_frame(task, regs);
+#ifdef CONFIG_FRAME_POINTER
+ if (!bp) {
+ if (task == current) {
+ /* Grab bp right from our regs */
+ get_bp(bp);
+ } else {
+ /* bp is the last reg pushed by switch_to */
+ bp = *(unsigned long *) task->thread.sp;
+ }
+ }
+#endif
+
for (;;) {
struct thread_info *context;
@@ -55,7 +65,7 @@ EXPORT_SYMBOL(dump_trace);
void
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, char *log_lvl)
+ unsigned long *sp, unsigned long bp, char *log_lvl)
{
unsigned long *stack;
int i;
@@ -77,7 +87,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
touch_nmi_watchdog();
}
printk(KERN_CONT "\n");
- show_trace_log_lvl(task, regs, sp, log_lvl);
+ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
@@ -102,7 +112,8 @@ void show_registers(struct pt_regs *regs)
u8 *ip;
printk(KERN_EMERG "Stack:\n");
- show_stack_log_lvl(NULL, regs, ®s->sp, KERN_EMERG);
+ show_stack_log_lvl(NULL, regs, ®s->sp,
+ 0, KERN_EMERG);
printk(KERN_EMERG "Code: ");
diff --git a/trunk/arch/x86/kernel/dumpstack_64.c b/trunk/arch/x86/kernel/dumpstack_64.c
index 64101335de19..6a340485249a 100644
--- a/trunk/arch/x86/kernel/dumpstack_64.c
+++ b/trunk/arch/x86/kernel/dumpstack_64.c
@@ -139,8 +139,8 @@ fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
* severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
*/
-void dump_trace(struct task_struct *task,
- struct pt_regs *regs, unsigned long *stack,
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
const struct stacktrace_ops *ops, void *data)
{
const unsigned cpu = get_cpu();
@@ -149,7 +149,6 @@ void dump_trace(struct task_struct *task,
unsigned used = 0;
struct thread_info *tinfo;
int graph = 0;
- unsigned long bp;
if (!task)
task = current;
@@ -161,7 +160,18 @@ void dump_trace(struct task_struct *task,
stack = (unsigned long *)task->thread.sp;
}
- bp = stack_frame(task, regs);
+#ifdef CONFIG_FRAME_POINTER
+ if (!bp) {
+ if (task == current) {
+ /* Grab bp right from our regs */
+ get_bp(bp);
+ } else {
+ /* bp is the last reg pushed by switch_to */
+ bp = *(unsigned long *) task->thread.sp;
+ }
+ }
+#endif
+
/*
* Print function call entries in all stacks, starting at the
* current stack address. If the stacks consist of nested
@@ -225,7 +235,7 @@ EXPORT_SYMBOL(dump_trace);
void
show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
- unsigned long *sp, char *log_lvl)
+ unsigned long *sp, unsigned long bp, char *log_lvl)
{
unsigned long *irq_stack_end;
unsigned long *irq_stack;
@@ -269,7 +279,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
preempt_enable();
printk(KERN_CONT "\n");
- show_trace_log_lvl(task, regs, sp, log_lvl);
+ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
void show_registers(struct pt_regs *regs)
@@ -298,7 +308,7 @@ void show_registers(struct pt_regs *regs)
printk(KERN_EMERG "Stack:\n");
show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
- KERN_EMERG);
+ regs->bp, KERN_EMERG);
printk(KERN_EMERG "Code: ");
diff --git a/trunk/arch/x86/kernel/entry_64.S b/trunk/arch/x86/kernel/entry_64.S
index e3ba417e8697..fe2690d71c0c 100644
--- a/trunk/arch/x86/kernel/entry_64.S
+++ b/trunk/arch/x86/kernel/entry_64.S
@@ -295,7 +295,6 @@ ENDPROC(native_usergs_sysret64)
.endm
/* save partial stack frame */
- .pushsection .kprobes.text, "ax"
ENTRY(save_args)
XCPT_FRAME
cld
@@ -335,7 +334,6 @@ ENTRY(save_args)
ret
CFI_ENDPROC
END(save_args)
- .popsection
ENTRY(save_rest)
PARTIAL_FRAME 1 REST_SKIP+8
diff --git a/trunk/arch/x86/kernel/hw_breakpoint.c b/trunk/arch/x86/kernel/hw_breakpoint.c
index 42c594254507..ff15c9dcc25d 100644
--- a/trunk/arch/x86/kernel/hw_breakpoint.c
+++ b/trunk/arch/x86/kernel/hw_breakpoint.c
@@ -433,10 +433,6 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
dr6_p = (unsigned long *)ERR_PTR(args->err);
dr6 = *dr6_p;
- /* If it's a single step, TRAP bits are random */
- if (dr6 & DR_STEP)
- return NOTIFY_DONE;
-
/* Do an early return if no trap bits are set in DR6 */
if ((dr6 & DR_TRAP_BITS) == 0)
return NOTIFY_DONE;
diff --git a/trunk/arch/x86/kernel/kgdb.c b/trunk/arch/x86/kernel/kgdb.c
index cd21b654dec6..ec592caac4b4 100644
--- a/trunk/arch/x86/kernel/kgdb.c
+++ b/trunk/arch/x86/kernel/kgdb.c
@@ -315,18 +315,14 @@ static void kgdb_remove_all_hw_break(void)
if (!breakinfo[i].enabled)
continue;
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
- if (!bp->attr.disabled) {
- arch_uninstall_hw_breakpoint(bp);
- bp->attr.disabled = 1;
+ if (bp->attr.disabled == 1)
continue;
- }
if (dbg_is_early)
early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
breakinfo[i].type);
- else if (hw_break_release_slot(i))
- printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n",
- breakinfo[i].addr);
- breakinfo[i].enabled = 0;
+ else
+ arch_uninstall_hw_breakpoint(bp);
+ bp->attr.disabled = 1;
}
}
diff --git a/trunk/arch/x86/kernel/msr.c b/trunk/arch/x86/kernel/msr.c
index 12fcbe2c143e..7bf2dc4c8f70 100644
--- a/trunk/arch/x86/kernel/msr.c
+++ b/trunk/arch/x86/kernel/msr.c
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/trunk/arch/x86/kernel/process.c b/trunk/arch/x86/kernel/process.c
index 96ed1aac543a..57d1868a86aa 100644
--- a/trunk/arch/x86/kernel/process.c
+++ b/trunk/arch/x86/kernel/process.c
@@ -91,7 +91,8 @@ void exit_thread(void)
void show_regs(struct pt_regs *regs)
{
show_registers(regs);
- show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs));
+ show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs),
+ regs->bp);
}
void show_regs_common(void)
diff --git a/trunk/arch/x86/kernel/smpboot.c b/trunk/arch/x86/kernel/smpboot.c
index 68f61ac632e1..083e99d1b7df 100644
--- a/trunk/arch/x86/kernel/smpboot.c
+++ b/trunk/arch/x86/kernel/smpboot.c
@@ -281,13 +281,6 @@ static void __cpuinit smp_callin(void)
*/
smp_store_cpu_info(cpuid);
- /*
- * This must be done before setting cpu_online_mask
- * or calling notify_cpu_starting.
- */
- set_cpu_sibling_map(raw_smp_processor_id());
- wmb();
-
notify_cpu_starting(cpuid);
/*
@@ -323,6 +316,16 @@ notrace static void __cpuinit start_secondary(void *unused)
*/
check_tsc_sync_target();
+ if (nmi_watchdog == NMI_IO_APIC) {
+ legacy_pic->mask(0);
+ enable_NMI_through_LVT0();
+ legacy_pic->unmask(0);
+ }
+
+ /* This must be done before setting cpu_online_mask */
+ set_cpu_sibling_map(raw_smp_processor_id());
+ wmb();
+
/*
* We need to hold call_lock, so there is no inconsistency
* between the time smp_call_function() determines number of
@@ -1058,6 +1061,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
printk(KERN_INFO "SMP mode deactivated.\n");
smpboot_clear_io_apic();
+ localise_nmi_watchdog();
+
connect_bsp_APIC();
setup_local_APIC();
end_local_APIC_setup();
@@ -1191,6 +1196,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
#endif
+ check_nmi_watchdog();
mtrr_aps_init();
}
@@ -1335,6 +1341,8 @@ int native_cpu_disable(void)
if (cpu == 0)
return -EBUSY;
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ stop_apic_nmi_watchdog(NULL);
clear_local_APIC();
cpu_disable_common();
diff --git a/trunk/arch/x86/kernel/stacktrace.c b/trunk/arch/x86/kernel/stacktrace.c
index 938c8e10a19a..b53c525368a7 100644
--- a/trunk/arch/x86/kernel/stacktrace.c
+++ b/trunk/arch/x86/kernel/stacktrace.c
@@ -73,22 +73,22 @@ static const struct stacktrace_ops save_stack_ops_nosched = {
*/
void save_stack_trace(struct stack_trace *trace)
{
- dump_trace(current, NULL, NULL, &save_stack_ops, trace);
+ dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
EXPORT_SYMBOL_GPL(save_stack_trace);
-void save_stack_trace_regs(struct stack_trace *trace, struct pt_regs *regs)
+void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp)
{
- dump_trace(current, regs, NULL, &save_stack_ops, trace);
+ dump_trace(current, NULL, NULL, bp, &save_stack_ops, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
{
- dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace);
+ dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
diff --git a/trunk/arch/x86/kernel/time.c b/trunk/arch/x86/kernel/time.c
index 25a28a245937..fb5cc5e14cfa 100644
--- a/trunk/arch/x86/kernel/time.c
+++ b/trunk/arch/x86/kernel/time.c
@@ -22,6 +22,10 @@
#include
#include
+#if defined(CONFIG_X86_32) && defined(CONFIG_X86_IO_APIC)
+int timer_ack;
+#endif
+
#ifdef CONFIG_X86_64
volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
#endif
@@ -59,6 +63,20 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
/* Keep nmi watchdog up to date */
inc_irq_stat(irq0_irqs);
+ /* Optimized out for !IO_APIC and x86_64 */
+ if (timer_ack) {
+ /*
+ * Subtle, when I/O APICs are used we have to ack timer IRQ
+ * manually to deassert NMI lines for the watchdog if run
+ * on an 82489DX-based system.
+ */
+ raw_spin_lock(&i8259A_lock);
+ outb(0x0c, PIC_MASTER_OCW3);
+ /* Ack the IRQ; AEOI will end it automatically. */
+ inb(PIC_MASTER_POLL);
+ raw_spin_unlock(&i8259A_lock);
+ }
+
global_clock_event->event_handler(global_clock_event);
/* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
diff --git a/trunk/arch/x86/kernel/traps.c b/trunk/arch/x86/kernel/traps.c
index f02c179c2552..cb838ca42c96 100644
--- a/trunk/arch/x86/kernel/traps.c
+++ b/trunk/arch/x86/kernel/traps.c
@@ -398,6 +398,15 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
== NOTIFY_STOP)
return;
+#ifndef CONFIG_LOCKUP_DETECTOR
+ /*
+ * Ok, so this is none of the documented NMI sources,
+ * so it must be the NMI watchdog.
+ */
+ if (nmi_watchdog_tick(regs, reason))
+ return;
+ if (!do_nmi_callback(regs, cpu))
+#endif /* !CONFIG_LOCKUP_DETECTOR */
unknown_nmi_error(reason, regs);
#else
unknown_nmi_error(reason, regs);
@@ -437,12 +446,14 @@ do_nmi(struct pt_regs *regs, long error_code)
void stop_nmi(void)
{
+ acpi_nmi_disable();
ignore_nmis++;
}
void restart_nmi(void)
{
ignore_nmis--;
+ acpi_nmi_enable();
}
/* May run on IST stack. */
diff --git a/trunk/arch/x86/kvm/svm.c b/trunk/arch/x86/kvm/svm.c
index 1ca12298ffc7..82e144a4e514 100644
--- a/trunk/arch/x86/kvm/svm.c
+++ b/trunk/arch/x86/kvm/svm.c
@@ -3395,7 +3395,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
load_host_msrs(vcpu);
- kvm_load_ldt(ldt_selector);
loadsegment(fs, fs_selector);
#ifdef CONFIG_X86_64
load_gs_index(gs_selector);
@@ -3403,6 +3402,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
#else
loadsegment(gs, gs_selector);
#endif
+ kvm_load_ldt(ldt_selector);
reload_tss(vcpu);
diff --git a/trunk/arch/x86/kvm/vmx.c b/trunk/arch/x86/kvm/vmx.c
index ff21fdda0c53..8da0e45ff7c9 100644
--- a/trunk/arch/x86/kvm/vmx.c
+++ b/trunk/arch/x86/kvm/vmx.c
@@ -821,9 +821,10 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
#endif
#ifdef CONFIG_X86_64
- rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
- if (is_long_mode(&vmx->vcpu))
+ if (is_long_mode(&vmx->vcpu)) {
+ rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+ }
#endif
for (i = 0; i < vmx->save_nmsrs; ++i)
kvm_set_shared_msr(vmx->guest_msrs[i].index,
@@ -838,23 +839,23 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
++vmx->vcpu.stat.host_state_reload;
vmx->host_state.loaded = 0;
-#ifdef CONFIG_X86_64
- if (is_long_mode(&vmx->vcpu))
- rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
-#endif
+ if (vmx->host_state.fs_reload_needed)
+ loadsegment(fs, vmx->host_state.fs_sel);
if (vmx->host_state.gs_ldt_reload_needed) {
kvm_load_ldt(vmx->host_state.ldt_sel);
#ifdef CONFIG_X86_64
load_gs_index(vmx->host_state.gs_sel);
+ wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
#else
loadsegment(gs, vmx->host_state.gs_sel);
#endif
}
- if (vmx->host_state.fs_reload_needed)
- loadsegment(fs, vmx->host_state.fs_sel);
reload_tss();
#ifdef CONFIG_X86_64
- wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+ if (is_long_mode(&vmx->vcpu)) {
+ rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+ wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+ }
#endif
if (current_thread_info()->status & TS_USEDFPU)
clts();
diff --git a/trunk/arch/x86/mm/kmemcheck/error.c b/trunk/arch/x86/mm/kmemcheck/error.c
index 704a37cedddb..af3b6c8a436f 100644
--- a/trunk/arch/x86/mm/kmemcheck/error.c
+++ b/trunk/arch/x86/mm/kmemcheck/error.c
@@ -185,7 +185,7 @@ void kmemcheck_error_save(enum kmemcheck_shadow state,
e->trace.entries = e->trace_entries;
e->trace.max_entries = ARRAY_SIZE(e->trace_entries);
e->trace.skip = 0;
- save_stack_trace_regs(&e->trace, regs);
+ save_stack_trace_bp(&e->trace, regs->bp);
/* Round address down to nearest 16 bytes */
shadow_copy = kmemcheck_shadow_lookup(address
diff --git a/trunk/arch/x86/oprofile/backtrace.c b/trunk/arch/x86/oprofile/backtrace.c
index 72cbec14d783..2d49d4e19a36 100644
--- a/trunk/arch/x86/oprofile/backtrace.c
+++ b/trunk/arch/x86/oprofile/backtrace.c
@@ -126,7 +126,7 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
if (!user_mode_vm(regs)) {
unsigned long stack = kernel_stack_pointer(regs);
if (depth)
- dump_trace(NULL, regs, (unsigned long *)stack,
+ dump_trace(NULL, regs, (unsigned long *)stack, 0,
&backtrace_ops, &depth);
return;
}
diff --git a/trunk/arch/x86/oprofile/nmi_timer_int.c b/trunk/arch/x86/oprofile/nmi_timer_int.c
index 0636dd93cef8..e3ecb71b5790 100644
--- a/trunk/arch/x86/oprofile/nmi_timer_int.c
+++ b/trunk/arch/x86/oprofile/nmi_timer_int.c
@@ -58,6 +58,9 @@ static void timer_stop(void)
int __init op_nmi_timer_init(struct oprofile_operations *ops)
{
+ if ((nmi_watchdog != NMI_IO_APIC) || (atomic_read(&nmi_active) <= 0))
+ return -ENODEV;
+
ops->start = timer_start;
ops->stop = timer_stop;
ops->cpu_type = "timer";
diff --git a/trunk/block/compat_ioctl.c b/trunk/block/compat_ioctl.c
index cc3eb78e333a..58c6ee5b010c 100644
--- a/trunk/block/compat_ioctl.c
+++ b/trunk/block/compat_ioctl.c
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include