Commit 42419bcd authored by Tobias Huschle's avatar Tobias Huschle Committed by Vasily Gorbik

s390/wti: Add wti accounting for missed grace periods

A virtual CPU that has received a warning-track interrupt may fail to
acknowledge the interrupt within the warning-track grace period.
While this is usually not a problem, it will become necessary to
investigate if there is a large number of such missed warning-track
interrupts. Therefore, it is necessary to track these events.
The information is tracked through the s390 debug facility and can be
found under /sys/kernel/debug/s390dbf/wti/.

The hex_ascii output is formatted as:
 <pid> <symbol>

The values pid and current psw are collected when a warning track
interrupt is received. Symbol is either the kernel symbol matching the
collected psw or redacted to <user> when running in user space.

Each line represents the currently executing process when a warning
track interrupt was received which was then not acknowledged within its
grace period.
Acked-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Reviewed-by: default avatarMete Durlu <meted@linux.ibm.com>
Signed-off-by: default avatarTobias Huschle <huschle@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent cafeff5a
...@@ -5,13 +5,25 @@ ...@@ -5,13 +5,25 @@
* Copyright IBM Corp. 2023 * Copyright IBM Corp. 2023
*/ */
#include <linux/kallsyms.h>
#include <linux/smpboot.h> #include <linux/smpboot.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <uapi/linux/sched/types.h> #include <uapi/linux/sched/types.h>
#include <asm/debug.h>
#include <asm/diag.h> #include <asm/diag.h>
#include <asm/sclp.h> #include <asm/sclp.h>
#define WTI_DBF_LEN 64
struct wti_debug {
unsigned long missed;
unsigned long addr;
pid_t pid;
};
struct wti_state { struct wti_state {
/* debug data for s390dbf */
struct wti_debug dbg;
/* /*
* Represents the real-time thread responsible to * Represents the real-time thread responsible to
* acknowledge the warning-track interrupt and trigger * acknowledge the warning-track interrupt and trigger
...@@ -27,6 +39,8 @@ struct wti_state { ...@@ -27,6 +39,8 @@ struct wti_state {
static DEFINE_PER_CPU(struct wti_state, wti_state); static DEFINE_PER_CPU(struct wti_state, wti_state);
static debug_info_t *wti_dbg;
/* /*
* During a warning-track grace period, interrupts are disabled * During a warning-track grace period, interrupts are disabled
* to prevent delays of the warning-track acknowledgment. * to prevent delays of the warning-track acknowledgment.
...@@ -61,6 +75,16 @@ static void wti_irq_enable(void) ...@@ -61,6 +75,16 @@ static void wti_irq_enable(void)
local_irq_restore(flags); local_irq_restore(flags);
} }
static void store_debug_data(struct wti_state *st)
{
struct pt_regs *regs = get_irq_regs();
st->dbg.pid = current->pid;
st->dbg.addr = 0;
if (!user_mode(regs))
st->dbg.addr = regs->psw.addr;
}
static void wti_interrupt(struct ext_code ext_code, static void wti_interrupt(struct ext_code ext_code,
unsigned int param32, unsigned long param64) unsigned int param32, unsigned long param64)
{ {
...@@ -68,6 +92,7 @@ static void wti_interrupt(struct ext_code ext_code, ...@@ -68,6 +92,7 @@ static void wti_interrupt(struct ext_code ext_code,
inc_irq_stat(IRQEXT_WTI); inc_irq_stat(IRQEXT_WTI);
wti_irq_disable(); wti_irq_disable();
store_debug_data(st);
st->pending = true; st->pending = true;
wake_up_process(st->thread); wake_up_process(st->thread);
} }
...@@ -79,6 +104,19 @@ static int wti_pending(unsigned int cpu) ...@@ -79,6 +104,19 @@ static int wti_pending(unsigned int cpu)
return st->pending; return st->pending;
} }
static void wti_dbf_grace_period(struct wti_state *st)
{
struct wti_debug *wdi = &st->dbg;
char buf[WTI_DBF_LEN];
if (wdi->addr)
snprintf(buf, sizeof(buf), "%d %pS", wdi->pid, (void *)wdi->addr);
else
snprintf(buf, sizeof(buf), "%d <user>", wdi->pid);
debug_text_event(wti_dbg, 2, buf);
wdi->missed++;
}
static void wti_thread_fn(unsigned int cpu) static void wti_thread_fn(unsigned int cpu)
{ {
struct wti_state *st = per_cpu_ptr(&wti_state, cpu); struct wti_state *st = per_cpu_ptr(&wti_state, cpu);
...@@ -89,7 +127,8 @@ static void wti_thread_fn(unsigned int cpu) ...@@ -89,7 +127,8 @@ static void wti_thread_fn(unsigned int cpu)
* resumes when hypervisor decides to dispatch CPU * resumes when hypervisor decides to dispatch CPU
* to this LPAR again. * to this LPAR again.
*/ */
diag49c(DIAG49C_SUBC_ACK); if (diag49c(DIAG49C_SUBC_ACK))
wti_dbf_grace_period(st);
wti_irq_enable(); wti_irq_enable();
} }
...@@ -129,7 +168,17 @@ static int __init wti_init(void) ...@@ -129,7 +168,17 @@ static int __init wti_init(void)
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
goto out_subclass; goto out_subclass;
} }
wti_dbg = debug_register("wti", 1, 1, WTI_DBF_LEN);
if (!wti_dbg) {
rc = -ENOMEM;
goto out_debug_register;
}
rc = debug_register_view(wti_dbg, &debug_hex_ascii_view);
if (rc)
goto out_debug_register;
goto out; goto out;
out_debug_register:
debug_unregister(wti_dbg);
out_subclass: out_subclass:
irq_subclass_unregister(IRQ_SUBCLASS_WARNING_TRACK); irq_subclass_unregister(IRQ_SUBCLASS_WARNING_TRACK);
unregister_external_irq(EXT_IRQ_WARNING_TRACK, wti_interrupt); unregister_external_irq(EXT_IRQ_WARNING_TRACK, wti_interrupt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment