[patch V3 13/14] genirq/proc: Runtime size the chip name

From: Thomas Gleixner

Date: Thu Mar 26 2026 - 18:02:09 EST


The chip name column in the /proc/interrupt output is 8 characters and
right aligned, which causes visual clutter due to the fixed length and the
alignment. Many interrupt chips, e.g. PCI/MSI[X] have way longer names.

Update the length when a chip is assigned to an interrupt and utilize this
information for the output. Align it left so all chip names start at the
begin of the column.

Update the GDB script as well.

Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Cc: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>
Cc: Kieran Bingham <kbingham@xxxxxxxxxx>
Cc: Florian Fainelli <florian.fainelli@xxxxxxxxxxxx>
---
V3: New patch
---
kernel/irq/chip.c | 6 ++++--
kernel/irq/internals.h | 8 ++------
kernel/irq/irqdomain.c | 3 +++
kernel/irq/proc.c | 33 ++++++++++++++++++++++++++++-----
kernel/irq/proc.h | 9 +++++++++
scripts/gdb/linux/interrupts.py | 25 ++++++++++++++++---------
6 files changed, 62 insertions(+), 22 deletions(-)

--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -46,9 +46,11 @@ int irq_set_chip(unsigned int irq, const
scoped_irqdesc->irq_data.chip = (struct irq_chip *)(chip ?: &no_irq_chip);
ret = 0;
}
- /* For !CONFIG_SPARSE_IRQ make the irq show up in allocated_irqs. */
- if (!ret)
+ if (!ret) {
+ /* For !CONFIG_SPARSE_IRQ make the irq show up in allocated_irqs. */
irq_mark_irq(irq);
+ irq_proc_update_chip(chip);
+ }
return ret;
}
EXPORT_SYMBOL(irq_set_chip);
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -12,6 +12,8 @@
#include <linux/rcuref.h>
#include <linux/sched/clock.h>

+#include "proc.h"
+
#ifdef CONFIG_SPARSE_IRQ
# define MAX_SPARSE_IRQS INT_MAX
#else
@@ -149,12 +151,6 @@ static inline void unregister_handler_pr
static inline void irq_proc_update_valid(struct irq_desc *desc) { }
#endif

-#if defined(CONFIG_PROC_FS) && defined(CONFIG_GENERIC_IRQ_SHOW)
-void irq_proc_calc_prec(void);
-#else
-static inline void irq_proc_calc_prec(void) { }
-#endif
-
struct irq_desc *irq_find_desc_at_or_after(unsigned int offset);

extern bool irq_can_set_affinity_usr(unsigned int irq);
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -20,6 +20,8 @@
#include <linux/smp.h>
#include <linux/fs.h>

+#include "proc.h"
+
static LIST_HEAD(irq_domain_list);
static DEFINE_MUTEX(irq_domain_mutex);

@@ -1532,6 +1534,7 @@ int irq_domain_set_hwirq_and_chip(struct
irq_data->chip = (struct irq_chip *)(chip ? chip : &no_irq_chip);
irq_data->chip_data = chip_data;

+ irq_proc_update_chip(chip);
return 0;
}
EXPORT_SYMBOL_GPL(irq_domain_set_hwirq_and_chip);
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -456,10 +456,14 @@ int __weak arch_show_interrupts(struct s
return 0;
}

+static DEFINE_RAW_SPINLOCK(irq_proc_constraints_lock);
+
static struct irq_proc_constraints {
unsigned int num_prec;
+ unsigned int chip_width;
} irq_proc_constraints __read_mostly = {
.num_prec = 3,
+ .chip_width = 8,
};

#ifndef ACTUAL_NR_IRQS
@@ -472,7 +476,23 @@ void irq_proc_calc_prec(void)

for (prec = 3, n = 1000; prec < 10 && n <= total_nr_irqs; ++prec)
n *= 10;
- WRITE_ONCE(irq_proc_constraints.num_prec, prec);
+
+ guard(raw_spinlock_irqsave)(&irq_proc_constraints_lock);
+ if (prec > irq_proc_constraints.num_prec)
+ WRITE_ONCE(irq_proc_constraints.num_prec, prec);
+}
+
+void irq_proc_update_chip(const struct irq_chip *chip)
+{
+ unsigned int len = chip && chip->name ? strlen(chip->name) : 0;
+
+ if (!len || len <= READ_ONCE(irq_proc_constraints.chip_width))
+ return;
+
+ /* Can be invoked from interrupt disabled contexts */
+ guard(raw_spinlock_irqsave)(&irq_proc_constraints_lock);
+ if (len > irq_proc_constraints.chip_width)
+ WRITE_ONCE(irq_proc_constraints.chip_width, len);
}

#define ZSTR1 " 0"
@@ -513,6 +533,7 @@ void irq_proc_emit_counts(struct seq_fil

int show_interrupts(struct seq_file *p, void *v)
{
+ unsigned int chip_width = READ_ONCE(irq_proc_constraints.chip_width);
unsigned int prec = READ_ONCE(irq_proc_constraints.num_prec);
int i = *(loff_t *) v, j;
struct irqaction *action;
@@ -548,18 +569,20 @@ int show_interrupts(struct seq_file *p,
irq_proc_emit_counts(p, &desc->kstat_irqs->cnt);
else
irq_proc_emit_zero_counts(p, num_online_cpus());
- seq_putc(p, ' ');
+
+ /* Enforce a visual gap */
+ seq_write(p, " ", 2);

guard(raw_spinlock_irq)(&desc->lock);
if (desc->irq_data.chip) {
if (desc->irq_data.chip->irq_print_chip)
desc->irq_data.chip->irq_print_chip(&desc->irq_data, p);
else if (desc->irq_data.chip->name)
- seq_printf(p, "%8s", desc->irq_data.chip->name);
+ seq_printf(p, "%-*s", chip_width, desc->irq_data.chip->name);
else
- seq_printf(p, "%8s", "-");
+ seq_printf(p, "%-*s", chip_width, "-");
} else {
- seq_printf(p, "%8s", "None");
+ seq_printf(p, "%-*s", chip_width, "None");
}

seq_putc(p, ' ');
--- /dev/null
+++ b/kernel/irq/proc.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_GENERIC_IRQ_SHOW)
+void irq_proc_calc_prec(void);
+void irq_proc_update_chip(const struct irq_chip *chip);
+#else
+static inline void irq_proc_calc_prec(void) { }
+static inline void irq_proc_update_chip(const struct irq_chip *chip) { }
+#endif
--- a/scripts/gdb/linux/interrupts.py
+++ b/scripts/gdb/linux/interrupts.py
@@ -20,7 +20,7 @@ irq_desc_type = utils.CachedType("struct
def irqd_is_level(desc):
return desc['irq_data']['common']['state_use_accessors'] & constants.LX_IRQD_LEVEL

-def show_irq_desc(prec, irq):
+def show_irq_desc(prec, chip_width, irq):
text = ""

desc = mapletree.mtree_load(gdb.parse_and_eval("&sparse_irqs"), irq)
@@ -48,7 +48,7 @@ irq_desc_type = utils.CachedType("struct
count = cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt']
else:
count = 0
- text += "%10u" % (count)
+ text += "%10u " % (count)

name = "None"
if desc['irq_data']['chip']:
@@ -58,7 +58,7 @@ irq_desc_type = utils.CachedType("struct
else:
name = "-"

- text += " %8s" % (name)
+ text += " %-*s" % (chip_width, name)

if desc['irq_data']['domain']:
text += " %*lu" % (prec, desc['irq_data']['hwirq'])
@@ -179,11 +179,18 @@ irq_desc_type = utils.CachedType("struct

def invoke(self, arg, from_tty):
nr_irqs = gdb.parse_and_eval("total_nr_irqs")
- prec = 3
- j = 1000
- while prec < 10 and j <= nr_irqs:
- prec += 1
- j *= 10
+ constr = utils.gdb_eval_or_none('irq_proc_constraints')
+
+ if constr:
+ prec = int(constr['num_prec'])
+ chip_width = int(constr['chip_width'])
+ else:
+ prec = 3
+ j = 1000
+ while prec < 10 and j <= nr_irqs:
+ prec += 1
+ j *= 10
+ chip_width = 8

gdb.write("%*s" % (prec + 8, ""))
for cpu in cpus.each_online_cpu():
@@ -194,7 +201,7 @@ irq_desc_type = utils.CachedType("struct
raise gdb.GdbError("Unable to find the sparse IRQ tree, is CONFIG_SPARSE_IRQ enabled?")

for irq in range(nr_irqs):
- gdb.write(show_irq_desc(prec, irq))
+ gdb.write(show_irq_desc(prec, chip_width, irq))
gdb.write(arch_show_interrupts(prec))