← Back to team overview

ubuntu-support-team team mailing list archive

[Merge] ~gpiccoli/ubuntu-support-tools/+git/ubuntu-support-tools:irq_dump into ubuntu-support-tools:master

 

Guilherme G. Piccoli has proposed merging ~gpiccoli/ubuntu-support-tools/+git/ubuntu-support-tools:irq_dump into ubuntu-support-tools:master.

Commit message:
    kernel: Add irq-dump module/tool
    
    This commits adds the irq-dump module, which is a debug tool to
    correlate do_irq() messsages like "do_IRQ: 4.36 No irq handler for vector"
    with IRQ numbers in /proc/interrupts.
    
    The do_irq() messages show cpu_number.vector information only,
    so with this module loaded users can "cat /proc/irq_dump" to see
    the relation of all vectors from all CPUs.
    
    The version uploaded here was built/tested in kernels v4.15 and
    v4.18. This work was a joint-effort from Gavin Guo (gavin),
    Maurício Oliveira (mfo) and I, during a SF debug case in 2018.
    
    Reference: SF #181058
    
    Signed-off-by: Guilherme G. Piccoli <gpiccoli@xxxxxxxxxxxxx>


Requested reviews:
  Ubuntu Support Team (ubuntu-support-team)

For more details, see:
https://code.launchpad.net/~gpiccoli/ubuntu-support-tools/+git/ubuntu-support-tools/+merge/366486
-- 
Your team Ubuntu Support Team is requested to review the proposed merge of ~gpiccoli/ubuntu-support-tools/+git/ubuntu-support-tools:irq_dump into ubuntu-support-tools:master.
diff --git a/kernel/irq-dump.c b/kernel/irq-dump.c
new file mode 100644
index 0000000..0ea8ef4
--- /dev/null
+++ b/kernel/irq-dump.c
@@ -0,0 +1,184 @@
+/* This module provides a procfs interface to dump information of
+ * interrupts, specially the IRQ number, io-apic cpu vector number
+ * for that interrupt, irq name and PCI device address (in case it
+ * is a PCI device irq). Useful to match "do_IRQ: XX.YY" messages
+ * with IRQ numbers.
+ *
+ * This version was tested with kernels 4.15 and 4.18.
+ *
+ * Build instructions:
+ * touch Makefile
+ * make -C /lib/modules/$(uname -r)/build M=$PWD obj-m=irq-dump.o
+ *
+ * Usage:
+ * Load the module and run "cat /proc/irq_dump" .
+ *
+ * Gavin Guo
+ * Guilherme G. Piccoli
+ * Maurício Faria de Oliveira
+ * Canonical (2018)
+*/
+
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+
+static void dump_percpu_vectors(struct seq_file *p)
+{
+	int cpu, vector;
+
+	vector_irq_t *vector_irq = (vector_irq_t *) kallsyms_lookup_name("vector_irq");
+	if (!vector_irq)
+		return;
+
+	for_each_online_cpu(cpu) {
+		for (vector = 0; vector < NR_VECTORS; ++vector) {
+			struct irq_desc *desc;
+			struct pci_dev *dev = NULL;
+
+			desc = per_cpu(*vector_irq, cpu)[vector];
+			if (!desc)
+				continue;
+
+			if (desc && desc->irq_common_data.msi_desc && desc->irq_common_data.msi_desc->dev) {
+				dev = to_pci_dev(desc->irq_common_data.msi_desc->dev);
+				if (dev) {
+				seq_printf(p, "cpu %2i, vector %3i, irq %3i, pci %02x:%02x.%x\n",
+					cpu, vector, desc->irq_data.irq,
+					dev->bus->number,
+					(dev->devfn & 0xf8) >> 3,
+					dev->devfn & 0x7);
+				continue;
+				}
+			}
+
+			seq_printf(p, "cpu %2i, vector %3i, irq %3i\n",
+				cpu, vector, desc->irq_data.irq);
+		}
+	}
+}
+
+static void *int_seq_start(struct seq_file *f, loff_t *pos)
+{
+	return (*pos <= nr_irqs) ? pos : NULL;
+}
+
+static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	(*pos)++;
+	if (*pos > nr_irqs)
+		return NULL;
+	return pos;
+}
+
+static void int_seq_stop(struct seq_file *f, void *v)
+{
+	/* Nothing to do here */
+}
+
+int show_irq_dump(struct seq_file *p, void *v)
+{
+	static int prec;
+
+	int vector;
+	int i = *(loff_t *) v;
+	struct irqaction *action;
+	struct irq_desc *desc;
+	struct irq_cfg *cfg;
+
+
+	if (i > nr_irqs)
+		return 0;
+
+	if (i == 0) {
+		prec = 3;
+	}
+
+	desc = irq_to_desc(i);
+	if (!desc)
+		goto out;
+
+	action = desc->action;
+	if (!action)
+		goto out;
+
+	seq_printf(p, "%*d: ", prec, i);
+
+	cfg = irq_get_chip_data(i);
+	if (cfg) {
+		vector = cfg->vector;
+		seq_printf(p, " vec=%3d ", vector);
+	}
+
+	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);
+		else
+			seq_printf(p, " %8s", "-");
+	} else {
+		seq_printf(p, " %8s", "None");
+	}
+	if (desc->irq_data.domain)
+		seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq);
+#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
+	seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
+#endif
+	if (desc->name)
+		seq_printf(p, "-%-8s", desc->name);
+
+	if (action) {
+		seq_printf(p, "  %s", action->name);
+		while ((action = action->next) != NULL)
+			seq_printf(p, ", %s", action->name);
+	}
+
+	seq_putc(p, '\n');
+	seq_putc(p, '\n');
+out:
+	if (i == nr_irqs) {
+		dump_percpu_vectors(p);
+		seq_putc(p, '\n');
+		seq_putc(p, '\n');
+	}
+	return 0;
+}
+
+static const struct seq_operations irq_dump_seq_ops = {
+	.start = int_seq_start,
+	.next  = int_seq_next,
+	.stop  = int_seq_stop,
+	.show  = show_irq_dump,
+};
+
+static int irq_dump_open(struct inode *inode, struct file *filp)
+{
+	return seq_open(filp, &irq_dump_seq_ops);
+}
+
+static const struct file_operations irq_dump_operations = {
+	.open		= irq_dump_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int irq_dump_init(void)
+{
+	proc_create("irq_dump", 0, NULL, &irq_dump_operations);
+	return 0;
+}
+
+static void irq_dump_exit(void) {
+	remove_proc_entry("irq_dump", NULL);
+}
+
+module_init(irq_dump_init);
+module_exit(irq_dump_exit);
+MODULE_LICENSE("GPL");
+

Follow ups