ubuntu-support-team team mailing list archive
-
ubuntu-support-team team
-
Mailing list archive
-
Message #00000
[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