Commit 930914b7 authored by Cédric Le Goater's avatar Cédric Le Goater Committed by Michael Ellerman
Browse files

powerpc/xive: Add a debugfs file to dump internal XIVE state



As does XMON, the debugfs file /sys/kernel/debug/powerpc/xive exposes
the XIVE internal state of the machine CPUs and interrupts. Available
on the PowerNV and sPAPR platforms.

Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
[mpe: Make the debugfs file 0400]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200306150143.5551-5-clg@kaod.org
parent 5191e0ba
Loading
Loading
Loading
Loading
+105 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/spinlock.h>
#include <linux/msi.h>

#include <asm/debugfs.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -1555,3 +1556,107 @@ static int __init xive_off(char *arg)
	return 0;
}
__setup("xive=off", xive_off);

void xive_debug_show_cpu(struct seq_file *m, int cpu)
{
	struct xive_cpu *xc = per_cpu(xive_cpu, cpu);

	seq_printf(m, "CPU %d:", cpu);
	if (xc) {
		seq_printf(m, "pp=%02x CPPR=%02x ", xc->pending_prio, xc->cppr);

#ifdef CONFIG_SMP
		{
			u64 val = xive_esb_read(&xc->ipi_data, XIVE_ESB_GET);

			seq_printf(m, "IPI=0x%08x PQ=%c%c ", xc->hw_ipi,
				   val & XIVE_ESB_VAL_P ? 'P' : '-',
				   val & XIVE_ESB_VAL_Q ? 'Q' : '-');
		}
#endif
		{
			struct xive_q *q = &xc->queue[xive_irq_priority];
			u32 i0, i1, idx;

			if (q->qpage) {
				idx = q->idx;
				i0 = be32_to_cpup(q->qpage + idx);
				idx = (idx + 1) & q->msk;
				i1 = be32_to_cpup(q->qpage + idx);
				seq_printf(m, "EQ idx=%d T=%d %08x %08x ...",
					   q->idx, q->toggle, i0, i1);
			}
		}
	}
	seq_puts(m, "\n");
}

void xive_debug_show_irq(struct seq_file *m, u32 hw_irq, struct irq_data *d)
{
	struct irq_chip *chip = irq_data_get_irq_chip(d);
	int rc;
	u32 target;
	u8 prio;
	u32 lirq;

	if (!is_xive_irq(chip))
		return;

	rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq);
	if (rc) {
		seq_printf(m, "IRQ 0x%08x : no config rc=%d\n", hw_irq, rc);
		return;
	}

	seq_printf(m, "IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",
		   hw_irq, target, prio, lirq);

	if (d) {
		struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
		u64 val = xive_esb_read(xd, XIVE_ESB_GET);

		seq_printf(m, "flags=%c%c%c PQ=%c%c",
			   xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ',
			   xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ',
			   xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ',
			   val & XIVE_ESB_VAL_P ? 'P' : '-',
			   val & XIVE_ESB_VAL_Q ? 'Q' : '-');
	}
	seq_puts(m, "\n");
}

static int xive_core_debug_show(struct seq_file *m, void *private)
{
	unsigned int i;
	struct irq_desc *desc;
	int cpu;

	if (xive_ops->debug_show)
		xive_ops->debug_show(m, private);

	for_each_possible_cpu(cpu)
		xive_debug_show_cpu(m, cpu);

	for_each_irq_desc(i, desc) {
		struct irq_data *d = irq_desc_get_irq_data(desc);
		unsigned int hw_irq;

		if (!d)
			continue;

		hw_irq = (unsigned int)irqd_to_hwirq(d);

		/* IPIs are special (HW number 0) */
		if (hw_irq)
			xive_debug_show_irq(m, hw_irq, d);
	}
	return 0;
}
DEFINE_SHOW_ATTRIBUTE(xive_core_debug);

int xive_core_debug_init(void)
{
	debugfs_create_file("xive", 0400, powerpc_debugfs_root,
			    NULL, &xive_core_debug_fops);
	return 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/cpumask.h>
#include <linux/mm.h>

#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -850,3 +851,5 @@ int xive_native_get_vp_state(u32 vp_id, u64 *out_state)
	return 0;
}
EXPORT_SYMBOL_GPL(xive_native_get_vp_state);

machine_arch_initcall(powernv, xive_core_debug_init);
+19 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/libfdt.h>

#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -645,6 +646,21 @@ static void xive_spapr_sync_source(u32 hw_irq)
	plpar_int_sync(0, hw_irq);
}

static int xive_spapr_debug_show(struct seq_file *m, void *private)
{
	struct xive_irq_bitmap *xibm;
	char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);

	list_for_each_entry(xibm, &xive_irq_bitmaps, list) {
		memset(buf, 0, PAGE_SIZE);
		bitmap_print_to_pagebuf(true, buf, xibm->bitmap, xibm->count);
		seq_printf(m, "bitmap #%d: %s", xibm->count, buf);
	}
	kfree(buf);

	return 0;
}

static const struct xive_ops xive_spapr_ops = {
	.populate_irq_data	= xive_spapr_populate_irq_data,
	.configure_irq		= xive_spapr_configure_irq,
@@ -662,6 +678,7 @@ static const struct xive_ops xive_spapr_ops = {
#ifdef CONFIG_SMP
	.get_ipi		= xive_spapr_get_ipi,
	.put_ipi		= xive_spapr_put_ipi,
	.debug_show		= xive_spapr_debug_show,
#endif /* CONFIG_SMP */
	.name			= "spapr",
};
@@ -839,3 +856,5 @@ bool __init xive_spapr_init(void)
	pr_info("Using %dkB queues\n", 1 << (xive_queue_shift - 10));
	return true;
}

machine_arch_initcall(pseries, xive_core_debug_init);
+2 −0
Original line number Diff line number Diff line
@@ -57,12 +57,14 @@ struct xive_ops {
	int	(*get_ipi)(unsigned int cpu, struct xive_cpu *xc);
	void	(*put_ipi)(unsigned int cpu, struct xive_cpu *xc);
#endif
	int	(*debug_show)(struct seq_file *m, void *private);
	const char *name;
};

bool xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset,
		    u8 max_prio);
__be32 *xive_queue_page_alloc(unsigned int cpu, u32 queue_shift);
int xive_core_debug_init(void);

static inline u32 xive_alloc_order(u32 queue_shift)
{