summaryrefslogtreecommitdiffstats
path: root/kernel/irq/debugfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/irq/debugfs.c')
-rw-r--r--kernel/irq/debugfs.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
new file mode 100644
index 000000000000..50ee2f6593e8
--- /dev/null
+++ b/kernel/irq/debugfs.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright 2017 Thomas Gleixner <tglx@linutronix.de>
3 *
4 * This file is licensed under the GPL V2.
5 */
6#include <linux/debugfs.h>
7#include <linux/irqdomain.h>
8#include <linux/irq.h>
9
10#include "internals.h"
11
12static struct dentry *irq_dir;
13
14struct irq_bit_descr {
15 unsigned int mask;
16 char *name;
17};
18#define BIT_MASK_DESCR(m) { .mask = m, .name = #m }
19
20static void irq_debug_show_bits(struct seq_file *m, int ind, unsigned int state,
21 const struct irq_bit_descr *sd, int size)
22{
23 int i;
24
25 for (i = 0; i < size; i++, sd++) {
26 if (state & sd->mask)
27 seq_printf(m, "%*s%s\n", ind + 12, "", sd->name);
28 }
29}
30
31#ifdef CONFIG_SMP
32static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc)
33{
34 struct irq_data *data = irq_desc_get_irq_data(desc);
35 struct cpumask *msk;
36
37 msk = irq_data_get_affinity_mask(data);
38 seq_printf(m, "affinity: %*pbl\n", cpumask_pr_args(msk));
39#ifdef CONFIG_GENERIC_PENDING_IRQ
40 msk = desc->pending_mask;
41 seq_printf(m, "pending: %*pbl\n", cpumask_pr_args(msk));
42#endif
43}
44#else
45static void irq_debug_show_masks(struct seq_file *m, struct irq_desc *desc) { }
46#endif
47
48static const struct irq_bit_descr irqchip_flags[] = {
49 BIT_MASK_DESCR(IRQCHIP_SET_TYPE_MASKED),
50 BIT_MASK_DESCR(IRQCHIP_EOI_IF_HANDLED),
51 BIT_MASK_DESCR(IRQCHIP_MASK_ON_SUSPEND),
52 BIT_MASK_DESCR(IRQCHIP_ONOFFLINE_ENABLED),
53 BIT_MASK_DESCR(IRQCHIP_SKIP_SET_WAKE),
54 BIT_MASK_DESCR(IRQCHIP_ONESHOT_SAFE),
55 BIT_MASK_DESCR(IRQCHIP_EOI_THREADED),
56};
57
58static void
59irq_debug_show_chip(struct seq_file *m, struct irq_data *data, int ind)
60{
61 struct irq_chip *chip = data->chip;
62
63 if (!chip) {
64 seq_printf(m, "chip: None\n");
65 return;
66 }
67 seq_printf(m, "%*schip: %s\n", ind, "", chip->name);
68 seq_printf(m, "%*sflags: 0x%lx\n", ind + 1, "", chip->flags);
69 irq_debug_show_bits(m, ind, chip->flags, irqchip_flags,
70 ARRAY_SIZE(irqchip_flags));
71}
72
73static void
74irq_debug_show_data(struct seq_file *m, struct irq_data *data, int ind)
75{
76 seq_printf(m, "%*sdomain: %s\n", ind, "",
77 data->domain ? data->domain->name : "");
78 seq_printf(m, "%*shwirq: 0x%lx\n", ind + 1, "", data->hwirq);
79 irq_debug_show_chip(m, data, ind + 1);
80#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
81 if (!data->parent_data)
82 return;
83 seq_printf(m, "%*sparent:\n", ind + 1, "");
84 irq_debug_show_data(m, data->parent_data, ind + 4);
85#endif
86}
87
88static const struct irq_bit_descr irqdata_states[] = {
89 BIT_MASK_DESCR(IRQ_TYPE_EDGE_RISING),
90 BIT_MASK_DESCR(IRQ_TYPE_EDGE_FALLING),
91 BIT_MASK_DESCR(IRQ_TYPE_LEVEL_HIGH),
92 BIT_MASK_DESCR(IRQ_TYPE_LEVEL_LOW),
93 BIT_MASK_DESCR(IRQD_LEVEL),
94
95 BIT_MASK_DESCR(IRQD_ACTIVATED),
96 BIT_MASK_DESCR(IRQD_IRQ_STARTED),
97 BIT_MASK_DESCR(IRQD_IRQ_DISABLED),
98 BIT_MASK_DESCR(IRQD_IRQ_MASKED),
99 BIT_MASK_DESCR(IRQD_IRQ_INPROGRESS),
100
101 BIT_MASK_DESCR(IRQD_PER_CPU),
102 BIT_MASK_DESCR(IRQD_NO_BALANCING),
103
104 BIT_MASK_DESCR(IRQD_MOVE_PCNTXT),
105 BIT_MASK_DESCR(IRQD_AFFINITY_SET),
106 BIT_MASK_DESCR(IRQD_SETAFFINITY_PENDING),
107 BIT_MASK_DESCR(IRQD_AFFINITY_MANAGED),
108 BIT_MASK_DESCR(IRQD_MANAGED_SHUTDOWN),
109
110 BIT_MASK_DESCR(IRQD_FORWARDED_TO_VCPU),
111
112 BIT_MASK_DESCR(IRQD_WAKEUP_STATE),
113 BIT_MASK_DESCR(IRQD_WAKEUP_ARMED),
114};
115
116static const struct irq_bit_descr irqdesc_states[] = {
117 BIT_MASK_DESCR(_IRQ_NOPROBE),
118 BIT_MASK_DESCR(_IRQ_NOREQUEST),
119 BIT_MASK_DESCR(_IRQ_NOTHREAD),
120 BIT_MASK_DESCR(_IRQ_NOAUTOEN),
121 BIT_MASK_DESCR(_IRQ_NESTED_THREAD),
122 BIT_MASK_DESCR(_IRQ_PER_CPU_DEVID),
123 BIT_MASK_DESCR(_IRQ_IS_POLLED),
124 BIT_MASK_DESCR(_IRQ_DISABLE_UNLAZY),
125};
126
127static const struct irq_bit_descr irqdesc_istates[] = {
128 BIT_MASK_DESCR(IRQS_AUTODETECT),
129 BIT_MASK_DESCR(IRQS_SPURIOUS_DISABLED),
130 BIT_MASK_DESCR(IRQS_POLL_INPROGRESS),
131 BIT_MASK_DESCR(IRQS_ONESHOT),
132 BIT_MASK_DESCR(IRQS_REPLAY),
133 BIT_MASK_DESCR(IRQS_WAITING),
134 BIT_MASK_DESCR(IRQS_PENDING),
135 BIT_MASK_DESCR(IRQS_SUSPENDED),
136};
137
138
139static int irq_debug_show(struct seq_file *m, void *p)
140{
141 struct irq_desc *desc = m->private;
142 struct irq_data *data;
143
144 raw_spin_lock_irq(&desc->lock);
145 data = irq_desc_get_irq_data(desc);
146 seq_printf(m, "handler: %pf\n", desc->handle_irq);
147 seq_printf(m, "status: 0x%08x\n", desc->status_use_accessors);
148 irq_debug_show_bits(m, 0, desc->status_use_accessors, irqdesc_states,
149 ARRAY_SIZE(irqdesc_states));
150 seq_printf(m, "istate: 0x%08x\n", desc->istate);
151 irq_debug_show_bits(m, 0, desc->istate, irqdesc_istates,
152 ARRAY_SIZE(irqdesc_istates));
153 seq_printf(m, "ddepth: %u\n", desc->depth);
154 seq_printf(m, "wdepth: %u\n", desc->wake_depth);
155 seq_printf(m, "dstate: 0x%08x\n", irqd_get(data));
156 irq_debug_show_bits(m, 0, irqd_get(data), irqdata_states,
157 ARRAY_SIZE(irqdata_states));
158 seq_printf(m, "node: %d\n", irq_data_get_node(data));
159 irq_debug_show_masks(m, desc);
160 irq_debug_show_data(m, data, 0);
161 raw_spin_unlock_irq(&desc->lock);
162 return 0;
163}
164
165static int irq_debug_open(struct inode *inode, struct file *file)
166{
167 return single_open(file, irq_debug_show, inode->i_private);
168}
169
170static const struct file_operations dfs_irq_ops = {
171 .open = irq_debug_open,
172 .read = seq_read,
173 .llseek = seq_lseek,
174 .release = single_release,
175};
176
177void irq_add_debugfs_entry(unsigned int irq, struct irq_desc *desc)
178{
179 char name [10];
180
181 if (!irq_dir || !desc || desc->debugfs_file)
182 return;
183
184 sprintf(name, "%d", irq);
185 desc->debugfs_file = debugfs_create_file(name, 0444, irq_dir, desc,
186 &dfs_irq_ops);
187}
188
189void irq_remove_debugfs_entry(struct irq_desc *desc)
190{
191 if (desc->debugfs_file)
192 debugfs_remove(desc->debugfs_file);
193}
194
195static int __init irq_debugfs_init(void)
196{
197 struct dentry *root_dir;
198 int irq;
199
200 root_dir = debugfs_create_dir("irq", NULL);
201 if (!root_dir)
202 return -ENOMEM;
203
204 irq_domain_debugfs_init(root_dir);
205
206 irq_dir = debugfs_create_dir("irqs", root_dir);
207
208 irq_lock_sparse();
209 for_each_active_irq(irq)
210 irq_add_debugfs_entry(irq, irq_to_desc(irq));
211 irq_unlock_sparse();
212
213 return 0;
214}
215__initcall(irq_debugfs_init);