Skip to content
This repository was archived by the owner on Apr 9, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions drivers/platform/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,12 @@ config INTEL_SCU_IPC_UTIL
low level access for debug work and updating the firmware. Say
N unless you will be doing this on an Intel MID platform.

config INTEL_TASKS_DUMP
bool "Intel panic tasks dumper"
depends on PRINTK
help
This provides a way to get full tasks dump in case of panic.

endif # X86_PLATFORM_DEVICES

config PMC_ATOM
Expand Down
1 change: 1 addition & 0 deletions drivers/platform/x86/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o
obj-$(CONFIG_WIRELESS_HOTKEY) += wireless-hotkey.o
obj-$(CONFIG_INTEL_TASKS_DUMP) += intel-tasks-dumper.o

# Intel uncore drivers
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
Expand Down
104 changes: 104 additions & 0 deletions drivers/platform/x86/intel-tasks-dumper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Intel Trace Hub to USB dvc-trace driver
*
* Copyright (C) 2015, Intel Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__

#include <linux/module.h>
#include <linux/console.h>
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/panic_notifier.h>

static const char * const filter[] = {
"hung_task:", /* hung task */
"Watchdog detected", /* Hard lockup */
"softlockup:", /* Soft lockup */
"Kernel Watchdog", /* iTCO warning */
};

static int force_en;
module_param(force_en, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(force_en, "Force enable");

static int force_dis;
module_param(force_dis, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(force_dis, "Force disable");

/* 1 pass, 0 not*/
static int check_filter(const char *v)
{
int i;

if (force_dis)
return 0;

if (force_en)
return 1;

for (i = 0; i < (sizeof(filter) / sizeof(*filter)); i++) {
if (!strncmp(v, filter[i], strlen(filter[i]))) {
pr_debug("Matching filter[%d] %s", i, filter[i]);
return 1;
}
}
return 0;
}

static int intel_task_panic_hndl(struct notifier_block *n,
unsigned long val, void *v)
{
char *buf = v;

/* for panic val is hardcoded to 0 */
if (val) {
return NOTIFY_OK;
} else if (!check_filter(buf)) {
pr_info("Skip tasks dumper.\n");
return NOTIFY_OK;
}

console_suspend_slow();
pr_info(" --- tasks dumper [BEGIN] ---\n");
show_state_filter(0);
pr_info(" --- tasks dumper [END] ---\n");
console_restore_slow();

/* maybe NOTIFY_STOP_MASK ....*/
return NOTIFY_OK;
}

static struct notifier_block panic_notifier = {
.notifier_call = intel_task_panic_hndl,
.priority = 2, /*Not the last one*/
};

static int __init intel_tasks_dumper_init(void)
{
pr_info("Register tasks dumper\n");
atomic_notifier_chain_register(&panic_notifier_list, &panic_notifier);
return 0;
}

static void __exit intel_tasks_dumper_exit(void)
{
atomic_notifier_chain_unregister(&panic_notifier_list, &panic_notifier);
}

module_init(intel_tasks_dumper_init);
module_exit(intel_tasks_dumper_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Traian Schiau <traianx.schiau@intel.com>");
2 changes: 1 addition & 1 deletion fs/pstore/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ static void pstore_register_console(void)
* Always initialize flags here since prior unregister_console()
* calls may have changed settings (specifically CON_ENABLED).
*/
pstore_console.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME;
pstore_console.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME | CON_IGNORELEVEL | CON_FAST;
register_console(&pstore_console);
}

Expand Down
5 changes: 5 additions & 0 deletions include/linux/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ static inline int con_debug_leave(void)
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
#define CON_BRL (32) /* Used for a braille device */
#define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */
#define CON_IGNORELEVEL (128) /* Used to ignore log level for a console */
#define CON_FAST (256) /* This is a fast console */

struct console {
char name[16];
Expand Down Expand Up @@ -225,4 +227,7 @@ extern void console_init(void);
void dummycon_register_output_notifier(struct notifier_block *nb);
void dummycon_unregister_output_notifier(struct notifier_block *nb);

void console_suspend_slow(void);
void console_restore_slow(void);

#endif /* _LINUX_CONSOLE_H */
60 changes: 53 additions & 7 deletions kernel/printk/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ u32 log_buf_len_get(void)
}
EXPORT_SYMBOL_GPL(log_buf_len_get);

/* Give the posibility to temporary disable slow (!CON_FAST) consoles */
static atomic_t console_slow_suspended = ATOMIC_INIT(0);
/* Keep the number of slow suspend in check */
#define MAX_SLOW_SUSPEND_COUNT (50)

/*
* Define how much of the log buffer we could take at maximum. The value
* must be greater than two. Note that only half of the buffer is available
Expand Down Expand Up @@ -957,6 +962,7 @@ void log_buf_vmcoreinfo_setup(void)
VMCOREINFO_OFFSET(printk_info, ts_nsec);
VMCOREINFO_OFFSET(printk_info, text_len);
VMCOREINFO_OFFSET(printk_info, caller_id);
VMCOREINFO_OFFSET(printk_info, print_cpu);
VMCOREINFO_OFFSET(printk_info, dev_info);

VMCOREINFO_STRUCT_SIZE(dev_printk_info);
Expand Down Expand Up @@ -1068,6 +1074,7 @@ static unsigned int __init add_to_rb(struct printk_ringbuffer *rb,
dest_r.info->flags = r->info->flags;
dest_r.info->ts_nsec = r->info->ts_nsec;
dest_r.info->caller_id = r->info->caller_id;
dest_r.info->print_cpu = r->info->print_cpu;
memcpy(&dest_r.info->dev_info, &r->info->dev_info, sizeof(dest_r.info->dev_info));

prb_final_commit(&e);
Expand Down Expand Up @@ -1210,7 +1217,11 @@ MODULE_PARM_DESC(ignore_loglevel,

static bool suppress_message_printing(int level)
{
#ifndef CON_IGNORELEVEL
return (level >= console_loglevel && !ignore_loglevel);
#else
return false;
#endif
}

#ifdef CONFIG_BOOT_PRINTK_DELAY
Expand Down Expand Up @@ -1276,12 +1287,12 @@ static size_t print_syslog(unsigned int level, char *buf)
return sprintf(buf, "<%u>", level);
}

static size_t print_time(u64 ts, char *buf)
static size_t print_time(u64 ts, u8 print_cpu, char *buf)
{
unsigned long rem_nsec = do_div(ts, 1000000000);

return sprintf(buf, "[%5lu.%06lu]",
(unsigned long)ts, rem_nsec / 1000);
return sprintf(buf, "[%5lu.%06lu, %d]",
(unsigned long)ts, rem_nsec / 1000, print_cpu);
}

#ifdef CONFIG_PRINTK_CALLER
Expand Down Expand Up @@ -1309,7 +1320,7 @@ static size_t info_print_prefix(const struct printk_info *info, bool syslog,
len = print_syslog((info->facility << 3) | info->level, buf);

if (time)
len += print_time(info->ts_nsec, buf + len);
len += print_time(info->ts_nsec, info->print_cpu, buf + len);

len += print_caller(info->caller_id, buf + len);

Expand Down Expand Up @@ -1928,7 +1939,7 @@ static int console_trylock_spinning(void)
* log_buf[start] to log_buf[end - 1].
* The console_lock must be held.
*/
static void call_console_drivers(const char *ext_text, size_t ext_len,
static void call_console_drivers(int level, const char *ext_text, size_t ext_len,
const char *text, size_t len)
{
static char dropped_text[64];
Expand All @@ -1950,13 +1961,19 @@ static void call_console_drivers(const char *ext_text, size_t ext_len,
for_each_console(con) {
if (exclusive_console && con != exclusive_console)
continue;
if (atomic_read(&console_slow_suspended) &&
!(con->flags & CON_FAST))
continue;
if (!(con->flags & CON_ENABLED))
continue;
if (!con->write)
continue;
if (!cpu_online(smp_processor_id()) &&
!(con->flags & CON_ANYTIME))
continue;
if (level >= console_loglevel &&
!(con->flags & CON_IGNORELEVEL) && !ignore_loglevel)
continue;
if (con->flags & CON_EXTENDED)
con->write(con, ext_text, ext_len);
else {
Expand Down Expand Up @@ -2234,6 +2251,7 @@ int vprintk_store(int facility, int level,
r.info->flags = flags & 0x1f;
r.info->ts_nsec = ts_nsec;
r.info->caller_id = caller_id;
r.info->print_cpu = raw_smp_processor_id();;
if (dev_info)
memcpy(&r.info->dev_info, dev_info, sizeof(r.info->dev_info));

Expand Down Expand Up @@ -2345,7 +2363,7 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
struct dev_printk_info *dev_info) { return 0; }
static void console_lock_spinning_enable(void) { }
static int console_lock_spinning_disable_and_check(void) { return 0; }
static void call_console_drivers(const char *ext_text, size_t ext_len,
static void call_console_drivers(int level, const char *ext_text, size_t ext_len,
const char *text, size_t len) {}
static bool suppress_message_printing(int level) { return false; }

Expand Down Expand Up @@ -2761,7 +2779,7 @@ void console_unlock(void)
console_lock_spinning_enable();

stop_critical_timings(); /* don't trace print latency */
call_console_drivers(ext_text, ext_len, text, len);
call_console_drivers(r.info->level, ext_text, ext_len, text, len);
start_critical_timings();

handover = console_lock_spinning_disable_and_check();
Expand Down Expand Up @@ -2852,6 +2870,34 @@ void console_flush_on_panic(enum con_flush_mode mode)
console_unlock();
}

void console_suspend_slow(void)
{
struct console *c;

if (atomic_read(&console_slow_suspended) >= MAX_SLOW_SUSPEND_COUNT) {
pr_debug("Max slow suspend\n");
return;
}
if (atomic_add_return(1, &console_slow_suspended) == 1) {
pr_err("Suspend slow consoles\n");
for_each_console(c)
if (!(c->flags & CON_FAST))
pr_debug("%s suspended\n", c->name);
}
}
EXPORT_SYMBOL(console_suspend_slow);

void console_restore_slow(void)
{
if (atomic_read(&console_slow_suspended) <= 0) {
pr_debug("Min slow suspend\n");
return;
}

if (!atomic_sub_return(1, &console_slow_suspended))
pr_err("Restore slow consoles\n");
}
EXPORT_SYMBOL(console_restore_slow);
/*
* Return the console tty driver structure and its associated index
*/
Expand Down
1 change: 1 addition & 0 deletions kernel/printk/printk_ringbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct printk_info {
u8 flags:5; /* internal record flags */
u8 level:3; /* syslog level */
u32 caller_id; /* thread id or processor id */
u32 print_cpu;

struct dev_printk_info dev_info;
};
Expand Down
10 changes: 10 additions & 0 deletions kernel/reboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,17 @@ void emergency_restart(void)
}
EXPORT_SYMBOL_GPL(emergency_restart);

#define REBOOT_WORK_TIMEOUT 60
static void reboot_timeout_fn(struct timer_list *unused)
{
pr_err("reboot/shutdown timeout!\n");
BUG();
}
static DEFINE_TIMER(reboot_timer, reboot_timeout_fn);

void kernel_restart_prepare(char *cmd)
{
mod_timer(&reboot_timer, jiffies + REBOOT_WORK_TIMEOUT * HZ);
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
usermodehelper_disable();
Expand Down Expand Up @@ -260,6 +269,7 @@ EXPORT_SYMBOL_GPL(kernel_restart);

static void kernel_shutdown_prepare(enum system_states state)
{
mod_timer(&reboot_timer, jiffies + REBOOT_WORK_TIMEOUT * HZ);
blocking_notifier_call_chain(&reboot_notifier_list,
(state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);
system_state = state;
Expand Down
4 changes: 2 additions & 2 deletions kernel/watchdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask);
#ifdef CONFIG_HARDLOCKUP_DETECTOR

# ifdef CONFIG_SMP
int __read_mostly sysctl_hardlockup_all_cpu_backtrace;
int __read_mostly sysctl_hardlockup_all_cpu_backtrace = 1;
# endif /* CONFIG_SMP */

/*
Expand Down Expand Up @@ -163,7 +163,7 @@ static void lockup_detector_update_enable(void)
#define SOFTLOCKUP_DELAY_REPORT ULONG_MAX

#ifdef CONFIG_SMP
int __read_mostly sysctl_softlockup_all_cpu_backtrace;
int __read_mostly sysctl_softlockup_all_cpu_backtrace = 1;
#endif

static struct cpumask watchdog_allowed_mask __read_mostly;
Expand Down