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

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
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -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);