xref: /linux/kernel/irq/proc.c (revision a33f32244d8550da8b4a26e277ce07d5c6d158b5)
1 /*
2  * linux/kernel/irq/proc.c
3  *
4  * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
5  *
6  * This file contains the /proc/irq/ handling code.
7  */
8 
9 #include <linux/irq.h>
10 #include <linux/gfp.h>
11 #include <linux/proc_fs.h>
12 #include <linux/seq_file.h>
13 #include <linux/interrupt.h>
14 
15 #include "internals.h"
16 
17 static struct proc_dir_entry *root_irq_dir;
18 
19 #ifdef CONFIG_SMP
20 
21 static int irq_affinity_proc_show(struct seq_file *m, void *v)
22 {
23 	struct irq_desc *desc = irq_to_desc((long)m->private);
24 	const struct cpumask *mask = desc->affinity;
25 
26 #ifdef CONFIG_GENERIC_PENDING_IRQ
27 	if (desc->status & IRQ_MOVE_PENDING)
28 		mask = desc->pending_mask;
29 #endif
30 	seq_cpumask(m, mask);
31 	seq_putc(m, '\n');
32 	return 0;
33 }
34 
35 #ifndef is_affinity_mask_valid
36 #define is_affinity_mask_valid(val) 1
37 #endif
38 
39 int no_irq_affinity;
40 static ssize_t irq_affinity_proc_write(struct file *file,
41 		const char __user *buffer, size_t count, loff_t *pos)
42 {
43 	unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data;
44 	cpumask_var_t new_value;
45 	int err;
46 
47 	if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity ||
48 	    irq_balancing_disabled(irq))
49 		return -EIO;
50 
51 	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
52 		return -ENOMEM;
53 
54 	err = cpumask_parse_user(buffer, count, new_value);
55 	if (err)
56 		goto free_cpumask;
57 
58 	if (!is_affinity_mask_valid(new_value)) {
59 		err = -EINVAL;
60 		goto free_cpumask;
61 	}
62 
63 	/*
64 	 * Do not allow disabling IRQs completely - it's a too easy
65 	 * way to make the system unusable accidentally :-) At least
66 	 * one online CPU still has to be targeted.
67 	 */
68 	if (!cpumask_intersects(new_value, cpu_online_mask)) {
69 		/* Special case for empty set - allow the architecture
70 		   code to set default SMP affinity. */
71 		err = irq_select_affinity_usr(irq) ? -EINVAL : count;
72 	} else {
73 		irq_set_affinity(irq, new_value);
74 		err = count;
75 	}
76 
77 free_cpumask:
78 	free_cpumask_var(new_value);
79 	return err;
80 }
81 
82 static int irq_affinity_proc_open(struct inode *inode, struct file *file)
83 {
84 	return single_open(file, irq_affinity_proc_show, PDE(inode)->data);
85 }
86 
87 static const struct file_operations irq_affinity_proc_fops = {
88 	.open		= irq_affinity_proc_open,
89 	.read		= seq_read,
90 	.llseek		= seq_lseek,
91 	.release	= single_release,
92 	.write		= irq_affinity_proc_write,
93 };
94 
95 static int default_affinity_show(struct seq_file *m, void *v)
96 {
97 	seq_cpumask(m, irq_default_affinity);
98 	seq_putc(m, '\n');
99 	return 0;
100 }
101 
102 static ssize_t default_affinity_write(struct file *file,
103 		const char __user *buffer, size_t count, loff_t *ppos)
104 {
105 	cpumask_var_t new_value;
106 	int err;
107 
108 	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
109 		return -ENOMEM;
110 
111 	err = cpumask_parse_user(buffer, count, new_value);
112 	if (err)
113 		goto out;
114 
115 	if (!is_affinity_mask_valid(new_value)) {
116 		err = -EINVAL;
117 		goto out;
118 	}
119 
120 	/*
121 	 * Do not allow disabling IRQs completely - it's a too easy
122 	 * way to make the system unusable accidentally :-) At least
123 	 * one online CPU still has to be targeted.
124 	 */
125 	if (!cpumask_intersects(new_value, cpu_online_mask)) {
126 		err = -EINVAL;
127 		goto out;
128 	}
129 
130 	cpumask_copy(irq_default_affinity, new_value);
131 	err = count;
132 
133 out:
134 	free_cpumask_var(new_value);
135 	return err;
136 }
137 
138 static int default_affinity_open(struct inode *inode, struct file *file)
139 {
140 	return single_open(file, default_affinity_show, PDE(inode)->data);
141 }
142 
143 static const struct file_operations default_affinity_proc_fops = {
144 	.open		= default_affinity_open,
145 	.read		= seq_read,
146 	.llseek		= seq_lseek,
147 	.release	= single_release,
148 	.write		= default_affinity_write,
149 };
150 #endif
151 
152 static int irq_spurious_proc_show(struct seq_file *m, void *v)
153 {
154 	struct irq_desc *desc = irq_to_desc((long) m->private);
155 
156 	seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n",
157 		   desc->irq_count, desc->irqs_unhandled,
158 		   jiffies_to_msecs(desc->last_unhandled));
159 	return 0;
160 }
161 
162 static int irq_spurious_proc_open(struct inode *inode, struct file *file)
163 {
164 	return single_open(file, irq_spurious_proc_show, NULL);
165 }
166 
167 static const struct file_operations irq_spurious_proc_fops = {
168 	.open		= irq_spurious_proc_open,
169 	.read		= seq_read,
170 	.llseek		= seq_lseek,
171 	.release	= single_release,
172 };
173 
174 #define MAX_NAMELEN 128
175 
176 static int name_unique(unsigned int irq, struct irqaction *new_action)
177 {
178 	struct irq_desc *desc = irq_to_desc(irq);
179 	struct irqaction *action;
180 	unsigned long flags;
181 	int ret = 1;
182 
183 	raw_spin_lock_irqsave(&desc->lock, flags);
184 	for (action = desc->action ; action; action = action->next) {
185 		if ((action != new_action) && action->name &&
186 				!strcmp(new_action->name, action->name)) {
187 			ret = 0;
188 			break;
189 		}
190 	}
191 	raw_spin_unlock_irqrestore(&desc->lock, flags);
192 	return ret;
193 }
194 
195 void register_handler_proc(unsigned int irq, struct irqaction *action)
196 {
197 	char name [MAX_NAMELEN];
198 	struct irq_desc *desc = irq_to_desc(irq);
199 
200 	if (!desc->dir || action->dir || !action->name ||
201 					!name_unique(irq, action))
202 		return;
203 
204 	memset(name, 0, MAX_NAMELEN);
205 	snprintf(name, MAX_NAMELEN, "%s", action->name);
206 
207 	/* create /proc/irq/1234/handler/ */
208 	action->dir = proc_mkdir(name, desc->dir);
209 }
210 
211 #undef MAX_NAMELEN
212 
213 #define MAX_NAMELEN 10
214 
215 void register_irq_proc(unsigned int irq, struct irq_desc *desc)
216 {
217 	char name [MAX_NAMELEN];
218 
219 	if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir)
220 		return;
221 
222 	memset(name, 0, MAX_NAMELEN);
223 	sprintf(name, "%d", irq);
224 
225 	/* create /proc/irq/1234 */
226 	desc->dir = proc_mkdir(name, root_irq_dir);
227 	if (!desc->dir)
228 		return;
229 
230 #ifdef CONFIG_SMP
231 	/* create /proc/irq/<irq>/smp_affinity */
232 	proc_create_data("smp_affinity", 0600, desc->dir,
233 			 &irq_affinity_proc_fops, (void *)(long)irq);
234 #endif
235 
236 	proc_create_data("spurious", 0444, desc->dir,
237 			 &irq_spurious_proc_fops, (void *)(long)irq);
238 }
239 
240 #undef MAX_NAMELEN
241 
242 void unregister_handler_proc(unsigned int irq, struct irqaction *action)
243 {
244 	if (action->dir) {
245 		struct irq_desc *desc = irq_to_desc(irq);
246 
247 		remove_proc_entry(action->dir->name, desc->dir);
248 	}
249 }
250 
251 static void register_default_affinity_proc(void)
252 {
253 #ifdef CONFIG_SMP
254 	proc_create("irq/default_smp_affinity", 0600, NULL,
255 		    &default_affinity_proc_fops);
256 #endif
257 }
258 
259 void init_irq_proc(void)
260 {
261 	unsigned int irq;
262 	struct irq_desc *desc;
263 
264 	/* create /proc/irq */
265 	root_irq_dir = proc_mkdir("irq", NULL);
266 	if (!root_irq_dir)
267 		return;
268 
269 	register_default_affinity_proc();
270 
271 	/*
272 	 * Create entries for all existing IRQs.
273 	 */
274 	for_each_irq_desc(irq, desc) {
275 		if (!desc)
276 			continue;
277 
278 		register_irq_proc(irq, desc);
279 	}
280 }
281 
282