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: Cédric Le Goater <clg@kaod.org>
[mpe: Make the debugfs file 0400]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200306150143.5551-5-clg@kaod.org
This commit is contained in:
Cédric Le Goater 2020-03-06 16:01:43 +01:00 committed by Michael Ellerman
parent 5191e0ba51
commit 930914b7d5
4 changed files with 129 additions and 0 deletions

View File

@ -20,6 +20,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <asm/debugfs.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/smp.h> #include <asm/smp.h>
@ -1555,3 +1556,107 @@ static int __init xive_off(char *arg)
return 0; return 0;
} }
__setup("xive=off", xive_off); __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;
}

View File

@ -19,6 +19,7 @@
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/machdep.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/smp.h> #include <asm/smp.h>
@ -850,3 +851,5 @@ int xive_native_get_vp_state(u32 vp_id, u64 *out_state)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(xive_native_get_vp_state); EXPORT_SYMBOL_GPL(xive_native_get_vp_state);
machine_arch_initcall(powernv, xive_core_debug_init);

View File

@ -18,6 +18,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/libfdt.h> #include <linux/libfdt.h>
#include <asm/machdep.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/smp.h> #include <asm/smp.h>
@ -645,6 +646,21 @@ static void xive_spapr_sync_source(u32 hw_irq)
plpar_int_sync(0, 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 = { static const struct xive_ops xive_spapr_ops = {
.populate_irq_data = xive_spapr_populate_irq_data, .populate_irq_data = xive_spapr_populate_irq_data,
.configure_irq = xive_spapr_configure_irq, .configure_irq = xive_spapr_configure_irq,
@ -662,6 +678,7 @@ static const struct xive_ops xive_spapr_ops = {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
.get_ipi = xive_spapr_get_ipi, .get_ipi = xive_spapr_get_ipi,
.put_ipi = xive_spapr_put_ipi, .put_ipi = xive_spapr_put_ipi,
.debug_show = xive_spapr_debug_show,
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
.name = "spapr", .name = "spapr",
}; };
@ -839,3 +856,5 @@ bool __init xive_spapr_init(void)
pr_info("Using %dkB queues\n", 1 << (xive_queue_shift - 10)); pr_info("Using %dkB queues\n", 1 << (xive_queue_shift - 10));
return true; return true;
} }
machine_arch_initcall(pseries, xive_core_debug_init);

View File

@ -57,12 +57,14 @@ struct xive_ops {
int (*get_ipi)(unsigned int cpu, struct xive_cpu *xc); int (*get_ipi)(unsigned int cpu, struct xive_cpu *xc);
void (*put_ipi)(unsigned int cpu, struct xive_cpu *xc); void (*put_ipi)(unsigned int cpu, struct xive_cpu *xc);
#endif #endif
int (*debug_show)(struct seq_file *m, void *private);
const char *name; const char *name;
}; };
bool xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset, bool xive_core_init(const struct xive_ops *ops, void __iomem *area, u32 offset,
u8 max_prio); u8 max_prio);
__be32 *xive_queue_page_alloc(unsigned int cpu, u32 queue_shift); __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) static inline u32 xive_alloc_order(u32 queue_shift)
{ {