]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
nmi_backtrace: generate one-line reports for idle cpus
authorChris Metcalf <cmetcalf@mellanox.com>
Sat, 8 Oct 2016 00:02:55 +0000 (17:02 -0700)
committerEthan Zhao <ethan.zhao@oracle.com>
Wed, 26 Jul 2017 06:46:14 +0000 (15:46 +0900)
When doing an nmi backtrace of many cores, most of which are idle, the
output is a little overwhelming and very uninformative.  Suppress
messages for cpus that are idling when they are interrupted and just
emit one line, "NMI backtrace for N skipped: idling at pc 0xNNN".

We do this by grouping all the cpuidle code together into a new
.cpuidle.text section, and then checking the address of the interrupted
PC to see if it lies within that section.

This commit suitably tags x86 and tile idle routines, and only adds in
the minimal framework for other architectures.

Link: http://lkml.kernel.org/r/1472487169-14923-5-git-send-email-cmetcalf@mellanox.com
Signed-off-by: Chris Metcalf <cmetcalf@mellanox.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Thompson <daniel.thompson@linaro.org> [arm]
Tested-by: Petr Mladek <pmladek@suse.com>
Cc: Aaron Tomlin <atomlin@redhat.com>
Cc: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
(cherry picked from commit 6727ad9e206cc08b80d8000a4d67f8417e53539d)

Orabug: 25925689

Signed-off-by: Ethan Zhao <ethan.zhao@oracle.com>
Reviewed-by: Jack Vogel <jack.vogel@oracle.com>
Conflicts:
arch/arm/kernel/vmlinux-xip.lds.S
arch/h8300/kernel/vmlinux.lds.S
arch/x86/kernel/process.c
drivers/acpi/processor_idle.c
kernel/sched/idle.c
lib/nmi_backtrace.c

49 files changed:
arch/alpha/kernel/vmlinux.lds.S
arch/arc/kernel/vmlinux.lds.S
arch/arm/kernel/vmlinux-xip.lds.S [new file with mode: 0644]
arch/arm/kernel/vmlinux.lds.S
arch/arm64/kernel/vmlinux.lds.S
arch/avr32/kernel/vmlinux.lds.S
arch/blackfin/kernel/vmlinux.lds.S
arch/c6x/kernel/vmlinux.lds.S
arch/cris/kernel/vmlinux.lds.S
arch/frv/kernel/vmlinux.lds.S
arch/h8300/kernel/vmlinux.lds.S [new file with mode: 0644]
arch/hexagon/kernel/vmlinux.lds.S
arch/ia64/kernel/vmlinux.lds.S
arch/m32r/kernel/vmlinux.lds.S
arch/m68k/kernel/vmlinux-nommu.lds
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/metag/kernel/vmlinux.lds.S
arch/microblaze/kernel/vmlinux.lds.S
arch/mips/kernel/vmlinux.lds.S
arch/mn10300/kernel/vmlinux.lds.S
arch/nios2/kernel/vmlinux.lds.S
arch/openrisc/kernel/vmlinux.lds.S
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/kernel/vmlinux.lds.S
arch/s390/kernel/vmlinux.lds.S
arch/score/kernel/vmlinux.lds.S
arch/sh/kernel/vmlinux.lds.S
arch/sparc/kernel/vmlinux.lds.S
arch/tile/kernel/entry.S
arch/tile/kernel/vmlinux.lds.S
arch/um/kernel/dyn.lds.S
arch/um/kernel/uml.lds.S
arch/unicore32/kernel/vmlinux.lds.S
arch/x86/include/asm/irqflags.h
arch/x86/kernel/acpi/cstate.c
arch/x86/kernel/process.c
arch/x86/kernel/vmlinux.lds.S
arch/xtensa/kernel/vmlinux.lds.S
drivers/acpi/processor_idle.c
drivers/cpuidle/driver.c
drivers/idle/intel_idle.c
include/asm-generic/vmlinux.lds.h
include/linux/cpu.h
kernel/sched/idle.c
lib/nmi_backtrace.c [new file with mode: 0644]
scripts/mod/modpost.c
scripts/recordmcount.c
scripts/recordmcount.pl

index 647b84c15382347ec25efae55067e77fff26693e..cebecfb76fbf6e87e02836651d5b7279cff00350 100644 (file)
@@ -22,6 +22,7 @@ SECTIONS
                HEAD_TEXT
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                *(.fixup)
                *(.gnu.warning)
index dd35bde39f6938e483b2cfd2a2e39a1cf2148c71..bb6d4fd4528c3f6b814cd38000fcf8ea70e2e2eb 100644 (file)
@@ -97,6 +97,7 @@ SECTIONS
                _text = .;
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                *(.fixup)
diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S
new file mode 100644 (file)
index 0000000..7fa487e
--- /dev/null
@@ -0,0 +1,317 @@
+/* ld script to make ARM Linux kernel
+ * taken from the i386 version by Russell King
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+
+#define PROC_INFO                                                      \
+       . = ALIGN(4);                                                   \
+       VMLINUX_SYMBOL(__proc_info_begin) = .;                          \
+       *(.proc.info.init)                                              \
+       VMLINUX_SYMBOL(__proc_info_end) = .;
+
+#define IDMAP_TEXT                                                     \
+       ALIGN_FUNCTION();                                               \
+       VMLINUX_SYMBOL(__idmap_text_start) = .;                         \
+       *(.idmap.text)                                                  \
+       VMLINUX_SYMBOL(__idmap_text_end) = .;                           \
+       . = ALIGN(PAGE_SIZE);                                           \
+       VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;                     \
+       *(.hyp.idmap.text)                                              \
+       VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
+
+#ifdef CONFIG_HOTPLUG_CPU
+#define ARM_CPU_DISCARD(x)
+#define ARM_CPU_KEEP(x)                x
+#else
+#define ARM_CPU_DISCARD(x)     x
+#define ARM_CPU_KEEP(x)
+#endif
+
+#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
+       defined(CONFIG_GENERIC_BUG)
+#define ARM_EXIT_KEEP(x)       x
+#define ARM_EXIT_DISCARD(x)
+#else
+#define ARM_EXIT_KEEP(x)
+#define ARM_EXIT_DISCARD(x)    x
+#endif
+
+OUTPUT_ARCH(arm)
+ENTRY(stext)
+
+#ifndef __ARMEB__
+jiffies = jiffies_64;
+#else
+jiffies = jiffies_64 + 4;
+#endif
+
+SECTIONS
+{
+       /*
+        * XXX: The linker does not define how output sections are
+        * assigned to input sections when there are multiple statements
+        * matching the same input section name.  There is no documented
+        * order of matching.
+        *
+        * unwind exit sections must be discarded before the rest of the
+        * unwind sections get included.
+        */
+       /DISCARD/ : {
+               *(.ARM.exidx.exit.text)
+               *(.ARM.extab.exit.text)
+               ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
+               ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
+               ARM_EXIT_DISCARD(EXIT_TEXT)
+               ARM_EXIT_DISCARD(EXIT_DATA)
+               EXIT_CALL
+#ifndef CONFIG_MMU
+               *(.text.fixup)
+               *(__ex_table)
+#endif
+#ifndef CONFIG_SMP_ON_UP
+               *(.alt.smp.init)
+#endif
+               *(.discard)
+               *(.discard.*)
+       }
+
+       . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
+       _xiprom = .;                    /* XIP ROM area to be mapped */
+
+       .head.text : {
+               _text = .;
+               HEAD_TEXT
+       }
+
+       .text : {                       /* Real text segment            */
+               _stext = .;             /* Text and read-only data      */
+                       IDMAP_TEXT
+                       __exception_text_start = .;
+                       *(.exception.text)
+                       __exception_text_end = .;
+                       IRQENTRY_TEXT
+                       TEXT_TEXT
+                       SCHED_TEXT
+                       CPUIDLE_TEXT
+                       LOCK_TEXT
+                       KPROBES_TEXT
+                       *(.gnu.warning)
+                       *(.glue_7)
+                       *(.glue_7t)
+               . = ALIGN(4);
+               *(.got)                 /* Global offset table          */
+                       ARM_CPU_KEEP(PROC_INFO)
+       }
+
+       RO_DATA(PAGE_SIZE)
+
+       . = ALIGN(4);
+       __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+               __start___ex_table = .;
+#ifdef CONFIG_MMU
+               *(__ex_table)
+#endif
+               __stop___ex_table = .;
+       }
+
+#ifdef CONFIG_ARM_UNWIND
+       /*
+        * Stack unwinding tables
+        */
+       . = ALIGN(8);
+       .ARM.unwind_idx : {
+               __start_unwind_idx = .;
+               *(.ARM.exidx*)
+               __stop_unwind_idx = .;
+       }
+       .ARM.unwind_tab : {
+               __start_unwind_tab = .;
+               *(.ARM.extab*)
+               __stop_unwind_tab = .;
+       }
+#endif
+
+       NOTES
+
+       _etext = .;                     /* End of text and rodata section */
+
+       /*
+        * The vectors and stubs are relocatable code, and the
+        * only thing that matters is their relative offsets
+        */
+       __vectors_start = .;
+       .vectors 0xffff0000 : AT(__vectors_start) {
+               *(.vectors)
+       }
+       . = __vectors_start + SIZEOF(.vectors);
+       __vectors_end = .;
+
+       __stubs_start = .;
+       .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) {
+               *(.stubs)
+       }
+       . = __stubs_start + SIZEOF(.stubs);
+       __stubs_end = .;
+
+       PROVIDE(vector_fiq_offset = vector_fiq - ADDR(.vectors));
+
+       INIT_TEXT_SECTION(8)
+       .exit.text : {
+               ARM_EXIT_KEEP(EXIT_TEXT)
+       }
+       .init.proc.info : {
+               ARM_CPU_DISCARD(PROC_INFO)
+       }
+       .init.arch.info : {
+               __arch_info_begin = .;
+               *(.arch.info.init)
+               __arch_info_end = .;
+       }
+       .init.tagtable : {
+               __tagtable_begin = .;
+               *(.taglist.init)
+               __tagtable_end = .;
+       }
+#ifdef CONFIG_SMP_ON_UP
+       .init.smpalt : {
+               __smpalt_begin = .;
+               *(.alt.smp.init)
+               __smpalt_end = .;
+       }
+#endif
+       .init.pv_table : {
+               __pv_table_begin = .;
+               *(.pv_table)
+               __pv_table_end = .;
+       }
+       .init.data : {
+               INIT_SETUP(16)
+               INIT_CALLS
+               CON_INITCALL
+               SECURITY_INITCALL
+               INIT_RAM_FS
+       }
+
+#ifdef CONFIG_SMP
+       PERCPU_SECTION(L1_CACHE_BYTES)
+#endif
+
+       _exiprom = .;                   /* End of XIP ROM area */
+       __data_loc = ALIGN(4);          /* location in binary */
+       . = PAGE_OFFSET + TEXT_OFFSET;
+
+       .data : AT(__data_loc) {
+               _data = .;              /* address in memory */
+               _sdata = .;
+
+               /*
+                * first, the init task union, aligned
+                * to an 8192 byte boundary.
+                */
+               INIT_TASK_DATA(THREAD_SIZE)
+
+               . = ALIGN(PAGE_SIZE);
+               __init_begin = .;
+               INIT_DATA
+               ARM_EXIT_KEEP(EXIT_DATA)
+               . = ALIGN(PAGE_SIZE);
+               __init_end = .;
+
+               NOSAVE_DATA
+               CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
+               READ_MOSTLY_DATA(L1_CACHE_BYTES)
+
+               /*
+                * and the usual data section
+                */
+               DATA_DATA
+               CONSTRUCTORS
+
+               _edata = .;
+       }
+       _edata_loc = __data_loc + SIZEOF(.data);
+
+#ifdef CONFIG_HAVE_TCM
+        /*
+        * We align everything to a page boundary so we can
+        * free it after init has commenced and TCM contents have
+        * been copied to its destination.
+        */
+       .tcm_start : {
+               . = ALIGN(PAGE_SIZE);
+               __tcm_start = .;
+               __itcm_start = .;
+       }
+
+       /*
+        * Link these to the ITCM RAM
+        * Put VMA to the TCM address and LMA to the common RAM
+        * and we'll upload the contents from RAM to TCM and free
+        * the used RAM after that.
+        */
+       .text_itcm ITCM_OFFSET : AT(__itcm_start)
+       {
+               __sitcm_text = .;
+               *(.tcm.text)
+               *(.tcm.rodata)
+               . = ALIGN(4);
+               __eitcm_text = .;
+       }
+
+       /*
+        * Reset the dot pointer, this is needed to create the
+        * relative __dtcm_start below (to be used as extern in code).
+        */
+       . = ADDR(.tcm_start) + SIZEOF(.tcm_start) + SIZEOF(.text_itcm);
+
+       .dtcm_start : {
+               __dtcm_start = .;
+       }
+
+       /* TODO: add remainder of ITCM as well, that can be used for data! */
+       .data_dtcm DTCM_OFFSET : AT(__dtcm_start)
+       {
+               . = ALIGN(4);
+               __sdtcm_data = .;
+               *(.tcm.data)
+               . = ALIGN(4);
+               __edtcm_data = .;
+       }
+
+       /* Reset the dot pointer or the linker gets confused */
+       . = ADDR(.dtcm_start) + SIZEOF(.data_dtcm);
+
+       /* End marker for freeing TCM copy in linked object */
+       .tcm_end : AT(ADDR(.dtcm_start) + SIZEOF(.data_dtcm)){
+               . = ALIGN(PAGE_SIZE);
+               __tcm_end = .;
+       }
+#endif
+
+       BSS_SECTION(0, 0, 0)
+       _end = .;
+
+       STABS_DEBUG
+}
+
+/*
+ * These must never be empty
+ * If you have to comment these two assert statements out, your
+ * binutils is too old (for other reasons as well)
+ */
+ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
+ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
+
+/*
+ * The HYP init code can't be more than a page long,
+ * and should not cross a page boundary.
+ * The above comment applies as well.
+ */
+ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
+       "HYP init code too big or misaligned")
index 8b60fde5ce48a628e5d1f2c682d2aa0684ed6642..6c13d570e9c9d1b4803af1396a410b903dbd3311 100644 (file)
@@ -107,6 +107,7 @@ SECTIONS
                        IRQENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
+                       CPUIDLE_TEXT
                        LOCK_TEXT
                        KPROBES_TEXT
                        *(.gnu.warning)
index a2c29865c3fe54e2d3c8c7ce1b956ba5ce5c0bf7..853f297b54f544513a83a87c63c85ff2a5c3b143 100644 (file)
@@ -93,6 +93,7 @@ SECTIONS
                        IRQENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
+                       CPUIDLE_TEXT
                        LOCK_TEXT
                        HYPERVISOR_TEXT
                        *(.fixup)
index a4589176bed5d7940d1f0e66d144a933892557f5..17f2730eb4978de7660933cbe04c233f6df78f14 100644 (file)
@@ -52,6 +52,7 @@ SECTIONS
                KPROBES_TEXT
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                *(.fixup)
                *(.gnu.warning)
index c9eec84aa258628d1c9d70fc545420dde30c8bc1..63a02c342830d0f002655fad6d4f2c31b165753a 100644 (file)
@@ -33,6 +33,7 @@ SECTIONS
 #ifndef CONFIG_SCHEDULE_L1
                SCHED_TEXT
 #endif
+               CPUIDLE_TEXT
                LOCK_TEXT
                IRQENTRY_TEXT
                KPROBES_TEXT
index 5a6e141d1641bced3bcabc94e66849bd337cbe3d..9cabd962ab36b084203d65ff6e08d25c56b9e755 100644 (file)
@@ -70,6 +70,7 @@ SECTIONS
                _stext = .;
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                IRQENTRY_TEXT
                KPROBES_TEXT
index a68b983dcea1bd413630c03e375f20a21baa5db8..e8a8235d6e1c26e83467df5e3735078d15955a9f 100644 (file)
@@ -42,6 +42,7 @@ SECTIONS
        .text : {
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                *(.fixup)
                *(.text.__*)
index 7e958d829ec9810020c75eca7beef1cbfd44a3c2..aa6e573d57da46d1cb05bec37cb9dfcc7bfac13f 100644 (file)
@@ -63,6 +63,7 @@ SECTIONS
        *(.text..tlbmiss)
        TEXT_TEXT
        SCHED_TEXT
+       CPUIDLE_TEXT
        LOCK_TEXT
 #ifdef CONFIG_DEBUG_INFO
        INIT_TEXT
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..7f11da1
--- /dev/null
@@ -0,0 +1,68 @@
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+
+#define ROMTOP 0x000000
+#define RAMTOP 0x400000
+
+jiffies = jiffies_64 + 4;
+
+ENTRY(_start)
+
+SECTIONS
+{
+#if defined(CONFIG_ROMKERNEL)
+       . = ROMTOP;
+       .vectors :
+       {
+       _vector = . ;
+               *(.vector*)
+       }
+#else
+       . = RAMTOP;
+       _ramstart = .;
+       . = . + CONFIG_OFFSET;
+#endif
+       _text = .;
+       HEAD_TEXT_SECTION
+       .text : {
+       _stext = . ;
+               TEXT_TEXT
+               SCHED_TEXT
+               CPUIDLE_TEXT
+               LOCK_TEXT
+#if defined(CONFIG_ROMKERNEL)
+               *(.int_redirect)
+#endif
+       _etext = . ;
+       }
+       EXCEPTION_TABLE(16)
+       NOTES
+       RO_DATA_SECTION(4)
+       ROMEND = .;
+#if defined(CONFIG_ROMKERNEL)
+       . = RAMTOP;
+       _ramstart = .;
+#define ADDR(x) ROMEND
+#endif
+       _sdata = . ;
+       __data_start = . ;
+       RW_DATA_SECTION(0, PAGE_SIZE, THREAD_SIZE)
+#if defined(CONFIG_ROMKERNEL)
+#undef ADDR
+#endif
+       . = ALIGN(0x4) ;
+       __init_begin = .;
+       INIT_TEXT_SECTION(4)
+       INIT_DATA_SECTION(4)
+       SECURITY_INIT
+       __init_end = .;
+       _edata = . ;
+       _begin_data = LOADADDR(.data);
+       _sbss =.;
+       BSS_SECTION(0, 0 ,0)
+       _ebss =.;
+       _ramend = .;
+       _end = .;
+       DISCARDS
+}
index 5f268c1071b3df8f56b4fd4871fbb1b5b19e8d72..ec87e67feb19e4692337fa78c82cc67b6ffd0dce 100644 (file)
@@ -50,6 +50,7 @@ SECTIONS
                _text = .;
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                *(.fixup)
index 84f8a52ac5ae2bdb65004691813aed4ed008ea9f..29c80056b2f6c3f2a1955906559bb3f708ca66d5 100644 (file)
@@ -46,6 +46,7 @@ SECTIONS {
                __end_ivt_text = .;
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                *(.gnu.linkonce.t*)
index 018e4a711d7927cef577e347dac93fb3a22afd75..ad1fe56455aae60b05b9e1a30294ccd2ab7b48ab 100644 (file)
@@ -31,6 +31,7 @@ SECTIONS
        HEAD_TEXT
        TEXT_TEXT
        SCHED_TEXT
+       CPUIDLE_TEXT
        LOCK_TEXT
        *(.fixup)
        *(.gnu.warning)
index 06a763f49fd34643d5330221a48011be00889b0e..d2c8abf1c8c4eac6688504f2a2dfaa7ea7177e65 100644 (file)
@@ -45,6 +45,7 @@ SECTIONS {
                HEAD_TEXT
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                *(.fixup)
                . = ALIGN(16);
index d0993594f558b3408317aede57c634c407ea580f..5b5ce1e4d1ed90b9e40dc68fa50c3b87671a8df0 100644 (file)
@@ -16,6 +16,7 @@ SECTIONS
        HEAD_TEXT
        TEXT_TEXT
        SCHED_TEXT
+       CPUIDLE_TEXT
        LOCK_TEXT
        *(.fixup)
        *(.gnu.warning)
index 8080469ee6c11c3e86ab59febaa4773790a2ffc7..fe5ea1974b16c2efcd34b0f134dcf17a24d388b5 100644 (file)
@@ -16,6 +16,7 @@ SECTIONS
        HEAD_TEXT
        TEXT_TEXT
        SCHED_TEXT
+       CPUIDLE_TEXT
        LOCK_TEXT
        *(.fixup)
        *(.gnu.warning)
index e12055e88bfe5e55b6092dbf3cf95dd63eb08cdd..9fc48354d519fa486c30b4a212c8c9f5e2e38dc4 100644 (file)
@@ -21,6 +21,7 @@ SECTIONS
   .text : {
        TEXT_TEXT
        SCHED_TEXT
+       CPUIDLE_TEXT
        LOCK_TEXT
        KPROBES_TEXT
        IRQENTRY_TEXT
index be9488d697347c330f9b226d1a5a5c9ba2d97714..5913c78630675a97df04666ec3426af12cfc7c5d 100644 (file)
@@ -33,6 +33,7 @@ SECTIONS {
                EXIT_TEXT
                EXIT_CALL
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index 3b46f7ce9ca75bc5f81f9bb2939880277289bd20..cffe97d1cf047e2758a826a2b8ed9a27aad7be39 100644 (file)
@@ -53,6 +53,7 @@ SECTIONS
        .text : {
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index 13c4814c29f840dd4ecb95e4e7206da7127aef49..2d5f1c3f1afbc54c9d34afb8396fc8bea326a295 100644 (file)
@@ -30,6 +30,7 @@ SECTIONS
        HEAD_TEXT
        TEXT_TEXT
        SCHED_TEXT
+       CPUIDLE_TEXT
        LOCK_TEXT
        KPROBES_TEXT
        *(.fixup)
index 326fab40a9de0c05cff1649b2080c4e8e493a2f4..340c7ab1d8b07b0a2dcbf7e37c98eeb92972fe85 100644 (file)
@@ -37,6 +37,7 @@ SECTIONS
        .text : {
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                IRQENTRY_TEXT
                KPROBES_TEXT
index 2d69a853b742e9ff3d7608b2b5ecfda1cf780941..6c3cf834b5d885a7e107c7ee93fac8163bd2afcc 100644 (file)
@@ -47,6 +47,7 @@ SECTIONS
           _stext = .;
          TEXT_TEXT
          SCHED_TEXT
+         CPUIDLE_TEXT
          LOCK_TEXT
          KPROBES_TEXT
          IRQENTRY_TEXT
index 0dacc5ca555afe7643da970bf9f3ae75ebc88790..1c91fc60cc075a4837d8c7025e6af30fb4ae0e35 100644 (file)
@@ -69,6 +69,7 @@ SECTIONS
        .text ALIGN(PAGE_SIZE) : {
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index 1db685104ffc2b298375c9062590ae1c2f811db9..ecba94a3f367a40ae7f57293fac2419bdb932a07 100644 (file)
@@ -52,6 +52,7 @@ SECTIONS
                /* careful! __ftr_alt_* sections need to be close to .text */
                *(.text .fixup __ftr_alt_* .ref.text)
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index 445657fe658cc62b4308f7fda4a23360dadfbb26..cbc74fd4a6db70c2f994351671e428da54434941 100644 (file)
@@ -25,6 +25,7 @@ SECTIONS
                HEAD_TEXT
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index 7274b5c4287ee4cbaad56a1eb41ad43a0d90c047..4117890b1db1a60dbfde5d26964a669cd53a2a80 100644 (file)
@@ -40,6 +40,7 @@ SECTIONS
                _text = .;      /* Text and read-only data */
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                *(.text.*)
index db88cbf9eafdc815d76d72784c18e4df42b361e5..989500c17358be28624d2586444998058592d0cb 100644 (file)
@@ -36,6 +36,7 @@ SECTIONS
                TEXT_TEXT
                EXTRA_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index f0f4ea82ec787d5b9e676ea2803b656b25607723..40162cc0b4d742338f7e667bc24b81d41e29561e 100644 (file)
@@ -45,6 +45,7 @@ SECTIONS
                HEAD_TEXT
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                IRQENTRY_TEXT
index 3d9175992a203391bd2918b4c59532257207b702..4a3d930eec035d544c3759d488d7ad8187c037cb 100644 (file)
@@ -57,7 +57,7 @@ STD_ENTRY(smp_nap)
  * When interrupted at _cpu_idle_nap, we bump the PC forward 8, and
  * as a result return to the function that called _cpu_idle().
  */
-STD_ENTRY(_cpu_idle)
+STD_ENTRY_SECTION(_cpu_idle, .cpuidle.text)
        movei r1, 1
        IRQ_ENABLE_LOAD(r2, r3)
        mtspr INTERRUPT_CRITICAL_SECTION, r1
index 0e059a0101ea3097527968bd2632a2b91436bb0d..a92931e8c4f9280cc5ed8b04871c1b96c30832af 100644 (file)
@@ -42,6 +42,7 @@ SECTIONS
   .text : AT (ADDR(.text) - LOAD_OFFSET) {
     HEAD_TEXT
     SCHED_TEXT
+    CPUIDLE_TEXT
     LOCK_TEXT
     KPROBES_TEXT
     IRQENTRY_TEXT
index adde088aeefff64f5820fcf1636e5b3afa3577ab..4fdbcf958cd5ad76b9756cb5f201fa384f119b68 100644 (file)
@@ -68,6 +68,7 @@ SECTIONS
     _stext = .;
     TEXT_TEXT
     SCHED_TEXT
+    CPUIDLE_TEXT
     LOCK_TEXT
     *(.fixup)
     *(.stub .text.* .gnu.linkonce.t.*)
index 6899195602b77fd3ed259f41977a2984faa902f4..1840f55ed0420b9ac2cc5db93d31a0b5a93fd48e 100644 (file)
@@ -28,6 +28,7 @@ SECTIONS
     _stext = .;
     TEXT_TEXT
     SCHED_TEXT
+    CPUIDLE_TEXT
     LOCK_TEXT
     *(.fixup)
     /* .gnu.warning sections are handled specially by elf32.em.  */
index 77e407e49a632c84cfb4957580c13dfbbebd1df4..56e788e8ee83cd8f56e54a186981a770fe0bba04 100644 (file)
@@ -37,6 +37,7 @@ SECTIONS
        .text : {               /* Real text segment */
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
 
                *(.fixup)
index b77f5edb03b0c02dc2047d52d07c9da447dba209..ac7692dcfa2e86196f47de38035731e39696d920 100644 (file)
@@ -4,6 +4,10 @@
 #include <asm/processor-flags.h>
 
 #ifndef __ASSEMBLY__
+
+/* Provide __cpuidle; we can't safely include <linux/cpu.h> */
+#define __cpuidle __attribute__((__section__(".cpuidle.text")))
+
 /*
  * Interrupt control:
  */
@@ -44,12 +48,12 @@ static inline void native_irq_enable(void)
        asm volatile("sti": : :"memory");
 }
 
-static inline void native_safe_halt(void)
+static inline __cpuidle void native_safe_halt(void)
 {
        asm volatile("sti; hlt": : :"memory");
 }
 
-static inline void native_halt(void)
+static inline __cpuidle void native_halt(void)
 {
        asm volatile("hlt": : :"memory");
 }
@@ -86,7 +90,7 @@ static inline notrace void arch_local_irq_enable(void)
  * Used in the idle loop; sti takes one instruction cycle
  * to complete:
  */
-static inline void arch_safe_halt(void)
+static inline __cpuidle void arch_safe_halt(void)
 {
        native_safe_halt();
 }
@@ -95,7 +99,7 @@ static inline void arch_safe_halt(void)
  * Used when interrupts are already enabled or to
  * shutdown the processor:
  */
-static inline void halt(void)
+static inline __cpuidle void halt(void)
 {
        native_halt();
 }
index 4b28159e0421d87bc36a1564cb32b6653314e86f..7efbb4d1902441942199e03f7d2624a249c2ba2f 100644 (file)
@@ -152,7 +152,7 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu,
 }
 EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
 
-void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
+void __cpuidle acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
 {
        unsigned int cpu = smp_processor_id();
        struct cstate_entry *percpu_entry;
index 9717437742489f39f1c47319b9649bb3961a580b..57c24319fa53d02a51a386bfa5e2b463b077f4d0 100644 (file)
@@ -335,7 +335,7 @@ void arch_cpu_idle(void)
 /*
  * We use this if we don't have any better idle routine..
  */
-void default_idle(void)
+void __cpuidle default_idle(void)
 {
        trace_cpu_idle_rcuidle(1, smp_processor_id());
        safe_halt();
@@ -449,8 +449,7 @@ static int prefer_mwait_c1_over_halt(const struct cpuinfo_x86 *c)
  * This invokes MWAIT with interrutps enabled and no flags,
  * which is backwards compatible with the original MWAIT implementation.
  */
-
-static void mwait_idle(void)
+static __cpuidle void mwait_idle(void)
 {
        if (!current_set_polling_and_test()) {
                trace_cpu_idle_rcuidle(1, smp_processor_id());
index 5f08871673eb63514015bc72822a5219f8f0d5ea..aeb549f04bca9d0dbf623ade2b390733ae9ac204 100644 (file)
@@ -98,6 +98,7 @@ SECTIONS
                _stext = .;
                TEXT_TEXT
                SCHED_TEXT
+               CPUIDLE_TEXT
                LOCK_TEXT
                KPROBES_TEXT
                ENTRY_TEXT
index fc1bc2ba8d5deb34348e783d82f6e0a0b919828a..cfda0b425442f44c427e111a528d624763cf6e3e 100644 (file)
@@ -93,6 +93,9 @@ SECTIONS
     VMLINUX_SYMBOL(__sched_text_start) = .;
     *(.sched.literal .sched.text)
     VMLINUX_SYMBOL(__sched_text_end) = .;
+    VMLINUX_SYMBOL(__cpuidle_text_start) = .;
+    *(.cpuidle.literal .cpuidle.text)
+    VMLINUX_SYMBOL(__cpuidle_text_end) = .;
     VMLINUX_SYMBOL(__lock_text_start) = .;
     *(.spinlock.literal .spinlock.text)
     VMLINUX_SYMBOL(__lock_text_end) = .;
index 39e0c8e36244f75aac3de4f09a0a89817e035b91..f488026ad91c3a5b3922effbe90588d0cf0aea27 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
 #include <linux/syscore_ops.h>
+#include <linux/cpu.h>
 #include <acpi/processor.h>
 
 /*
@@ -115,7 +116,7 @@ static struct dmi_system_id processor_power_dmi_table[] = {
  * Callers should disable interrupts before the call and enable
  * interrupts after return.
  */
-static void acpi_safe_halt(void)
+static void __cpuidle acpi_safe_halt(void)
 {
        if (!tif_need_resched()) {
                safe_halt();
@@ -684,7 +685,7 @@ static int acpi_idle_bm_check(void)
  *
  * Caller disables interrupt before call and enables interrupt after return.
  */
-static void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx)
 {
        if (cx->entry_method == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
index 5db147859b9047db626d66e64bef2897a41822f2..e99c8f17c0be2bb1341f1a0b63acbb2444127935 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/cpuidle.h>
 #include <linux/cpumask.h>
 #include <linux/tick.h>
+#include <linux/cpu.h>
 
 #include "cpuidle.h"
 
@@ -178,8 +179,8 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
 }
 
 #ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev,
-               struct cpuidle_driver *drv, int index)
+static int __cpuidle poll_idle(struct cpuidle_device *dev,
+                              struct cpuidle_driver *drv, int index)
 {
        local_irq_enable();
        if (!current_set_polling_and_test()) {
index 22473db328a18fd52819f176bf52cea05d6f181a..85d27da83ebe63264e35d9f83ea3f54bb39f661a 100644 (file)
@@ -836,8 +836,8 @@ static struct cpuidle_state bxt_cstates[] = {
  *
  * Must be called under local_irq_disable().
  */
-static int intel_idle(struct cpuidle_device *dev,
-               struct cpuidle_driver *drv, int index)
+static __cpuidle int intel_idle(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int index)
 {
        unsigned long ecx = 1; /* break on interrupt flag */
        struct cpuidle_state *state = &drv->states[index];
index 1839145b44a2d8890f971340d539ae8f2500f79c..d11dd70b6dba006c232dc9d17ecd076449d7d056 100644 (file)
                *(.spinlock.text)                                       \
                VMLINUX_SYMBOL(__lock_text_end) = .;
 
+#define CPUIDLE_TEXT                                                   \
+               ALIGN_FUNCTION();                                       \
+               VMLINUX_SYMBOL(__cpuidle_text_start) = .;               \
+               *(.cpuidle.text)                                        \
+               VMLINUX_SYMBOL(__cpuidle_text_end) = .;
+
 #define KPROBES_TEXT                                                   \
                ALIGN_FUNCTION();                                       \
                VMLINUX_SYMBOL(__kprobes_text_start) = .;               \
index c0fb6b1b4712c30bdf9f7749fefead8a5a2be622..d29d4c1052d4a943a257fd8ee3e6fb3e8b2026f3 100644 (file)
@@ -275,6 +275,11 @@ void cpu_startup_entry(enum cpuhp_state state);
 
 void cpu_idle_poll_ctrl(bool enable);
 
+/* Attach to any functions which should be considered cpuidle. */
+#define __cpuidle      __attribute__((__section__(".cpuidle.text")))
+
+bool cpu_in_idle(unsigned long pc);
+
 void arch_cpu_idle(void);
 void arch_cpu_idle_prepare(void);
 void arch_cpu_idle_enter(void);
index fefcb1fa5160139a41e9dd1fee74b20ef39105e0..cfc504aa8d9c552110cfb0942e4a572dae28928d 100644 (file)
 
 #include "sched.h"
 
+/* Linker adds these: start and end of __cpuidle functions */
+extern char __cpuidle_text_start[], __cpuidle_text_end[];
+
+/**
+ * sched_idle_set_state - Record idle state for the current CPU.
+ * @idle_state: State to record.
+ */
+void sched_idle_set_state(struct cpuidle_state *idle_state)
+{
+       idle_set_state(this_rq(), idle_state);
+}
+
 static int __read_mostly cpu_idle_force_poll;
 
 void cpu_idle_poll_ctrl(bool enable)
@@ -43,7 +55,7 @@ static int __init cpu_idle_nopoll_setup(char *__unused)
 __setup("hlt", cpu_idle_nopoll_setup);
 #endif
 
-static inline int cpu_idle_poll(void)
+static noinline int __cpuidle cpu_idle_poll(void)
 {
        rcu_idle_enter();
        trace_cpu_idle_rcuidle(0, smp_processor_id());
@@ -67,6 +79,43 @@ void __weak arch_cpu_idle(void)
        local_irq_enable();
 }
 
+/**
+ * default_idle_call - Default CPU idle routine.
+ *
+ * To use when the cpuidle framework cannot be used.
+ */
+void __cpuidle default_idle_call(void)
+{
+       if (current_clr_polling_and_test()) {
+               local_irq_enable();
+       } else {
+               stop_critical_timings();
+               arch_cpu_idle();
+               start_critical_timings();
+       }
+}
+
+static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev,
+                     int next_state)
+{
+       /*
+        * The idle task must be scheduled, it is pointless to go to idle, just
+        * update no idle residency and return.
+        */
+       if (current_clr_polling_and_test()) {
+               dev->last_residency = 0;
+               local_irq_enable();
+               return -EBUSY;
+       }
+
+       /*
+        * Enter the idle state previously returned by the governor decision.
+        * This function will block until an interrupt occurs and will take
+        * care of re-enabling the local interrupts
+        */
+       return cpuidle_enter(drv, dev, next_state);
+}
+
 /**
  * cpuidle_idle_call - the main idle function
  *
@@ -276,6 +325,12 @@ static void cpu_idle_loop(void)
        }
 }
 
+bool cpu_in_idle(unsigned long pc)
+{
+       return pc >= (unsigned long)__cpuidle_text_start &&
+               pc < (unsigned long)__cpuidle_text_end;
+}
+
 void cpu_startup_entry(enum cpuhp_state state)
 {
        /*
diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c
new file mode 100644 (file)
index 0000000..7555475
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  NMI backtrace support
+ *
+ * Gratuitously copied from arch/x86/kernel/apic/hw_nmi.c by Russell King,
+ * with the following header:
+ *
+ *  HW NMI watchdog support
+ *
+ *  started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
+ *
+ *  Arch specific calls to support NMI watchdog
+ *
+ *  Bits copied from original nmi.c file
+ */
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/kprobes.h>
+#include <linux/nmi.h>
+#include <linux/cpu.h>
+
+#ifdef arch_trigger_cpumask_backtrace
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
+/* "in progress" flag of arch_trigger_cpumask_backtrace */
+static unsigned long backtrace_flag;
+
+/*
+ * When raise() is called it will be passed a pointer to the
+ * backtrace_mask. Architectures that call nmi_cpu_backtrace()
+ * directly from their raise() functions may rely on the mask
+ * they are passed being updated as a side effect of this call.
+ */
+void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
+                                  bool exclude_self,
+                                  void (*raise)(cpumask_t *mask))
+{
+       int i, this_cpu = get_cpu();
+
+       if (test_and_set_bit(0, &backtrace_flag)) {
+               /*
+                * If there is already a trigger_all_cpu_backtrace() in progress
+                * (backtrace_flag == 1), don't output double cpu dump infos.
+                */
+               put_cpu();
+               return;
+       }
+
+       cpumask_copy(to_cpumask(backtrace_mask), mask);
+       if (exclude_self)
+               cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask));
+
+       /*
+        * Don't try to send an NMI to this cpu; it may work on some
+        * architectures, but on others it may not, and we'll get
+        * information at least as useful just by doing a dump_stack() here.
+        * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit.
+        */
+       if (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask)))
+               nmi_cpu_backtrace(NULL);
+
+       if (!cpumask_empty(to_cpumask(backtrace_mask))) {
+               pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n",
+                       this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask));
+               raise(to_cpumask(backtrace_mask));
+       }
+
+       /* 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);
+               touch_softlockup_watchdog();
+       }
+
+       /*
+        * Force flush any remote buffers that might be stuck in IRQ context
+        * and therefore could not run their irq_work.
+        */
+       printk_nmi_flush();
+
+       clear_bit_unlock(0, &backtrace_flag);
+       put_cpu();
+}
+
+bool nmi_cpu_backtrace(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+               if (regs && cpu_in_idle(instruction_pointer(regs))) {
+                       pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n",
+                               cpu, instruction_pointer(regs));
+               } else {
+                       pr_warn("NMI backtrace for cpu %d\n", cpu);
+                       if (regs)
+                               show_regs(regs);
+                       else
+                               dump_stack();
+               }
+               cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+               return true;
+       }
+
+       return false;
+}
+NOKPROBE_SYMBOL(nmi_cpu_backtrace);
+#endif
index 03d798228a458c1e236277b8b3e8d2e48ea093d9..b4b9ba8b6e7552eee8b7f5728c6fb1d286367601 100644 (file)
@@ -884,7 +884,7 @@ static void check_section(const char *modname, struct elf_info *elf,
 
 #define DATA_SECTIONS ".data", ".data.rel"
 #define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
-               ".kprobes.text"
+               ".kprobes.text", ".cpuidle.text"
 #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
                ".fixup", ".entry.text", ".exception.text", ".text.*"
 
index 3d1984e59a3016f29ecf84a97305ca8d9647b5ed..6c1486428aa4456cfec557e904148730859db3f2 100644 (file)
@@ -254,6 +254,7 @@ is_mcounted_section_name(char const *const txtname)
                strcmp(".spinlock.text", txtname) == 0 ||
                strcmp(".irqentry.text", txtname) == 0 ||
                strcmp(".kprobes.text", txtname) == 0 ||
+               strcmp(".cpuidle.text", txtname) == 0 ||
                strcmp(".text.unlikely", txtname) == 0;
 }
 
index 826470d7f00077278875a68c577bccbc7a82d5ea..f8be31c30ee277c53ba65feb38be3c154d494ab3 100755 (executable)
@@ -135,6 +135,7 @@ my %text_sections = (
      ".spinlock.text" => 1,
      ".irqentry.text" => 1,
      ".kprobes.text" => 1,
+     ".cpuidle.text" => 1,
      ".text.unlikely" => 1,
 );