diff options
author | Tobias Huschle <huschle@linux.ibm.com> | 2024-08-12 13:39:29 +0200 |
---|---|---|
committer | Vasily Gorbik <gor@linux.ibm.com> | 2024-08-29 22:56:34 +0200 |
commit | 42419bcdfdcb287918e53500a04aeb532b41ed1f (patch) | |
tree | 1bfa8fe14bda89016ee70b1b092a98a031c98e07 /arch/s390 | |
parent | cafeff5a030983bbf37b11ab766b68d7da3b8aab (diff) | |
download | linux-42419bcdfdcb287918e53500a04aeb532b41ed1f.tar.gz linux-42419bcdfdcb287918e53500a04aeb532b41ed1f.tar.bz2 linux-42419bcdfdcb287918e53500a04aeb532b41ed1f.zip |
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: Heiko Carstens <hca@linux.ibm.com>
Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Tobias Huschle <huschle@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kernel/wti.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/arch/s390/kernel/wti.c b/arch/s390/kernel/wti.c index 3abae3908e65..da8bbffbed9d 100644 --- a/arch/s390/kernel/wti.c +++ b/arch/s390/kernel/wti.c @@ -5,13 +5,25 @@ * Copyright IBM Corp. 2023 */ +#include <linux/kallsyms.h> #include <linux/smpboot.h> #include <linux/irq.h> #include <uapi/linux/sched/types.h> +#include <asm/debug.h> #include <asm/diag.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 { + /* debug data for s390dbf */ + struct wti_debug dbg; /* * Represents the real-time thread responsible to * acknowledge the warning-track interrupt and trigger @@ -27,6 +39,8 @@ struct 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 * to prevent delays of the warning-track acknowledgment. @@ -61,6 +75,16 @@ static void wti_irq_enable(void) 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, unsigned int param32, unsigned long param64) { @@ -68,6 +92,7 @@ static void wti_interrupt(struct ext_code ext_code, inc_irq_stat(IRQEXT_WTI); wti_irq_disable(); + store_debug_data(st); st->pending = true; wake_up_process(st->thread); } @@ -79,6 +104,19 @@ static int wti_pending(unsigned int cpu) 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) { struct wti_state *st = per_cpu_ptr(&wti_state, cpu); @@ -89,7 +127,8 @@ static void wti_thread_fn(unsigned int cpu) * resumes when hypervisor decides to dispatch CPU * to this LPAR again. */ - diag49c(DIAG49C_SUBC_ACK); + if (diag49c(DIAG49C_SUBC_ACK)) + wti_dbf_grace_period(st); wti_irq_enable(); } @@ -129,7 +168,17 @@ static int __init wti_init(void) rc = -EOPNOTSUPP; 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; +out_debug_register: + debug_unregister(wti_dbg); out_subclass: irq_subclass_unregister(IRQ_SUBCLASS_WARNING_TRACK); unregister_external_irq(EXT_IRQ_WARNING_TRACK, wti_interrupt); |