• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/kernel/irq/
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
17static struct proc_dir_entry *root_irq_dir;
18
19#ifdef CONFIG_SMP
20
21static 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
35static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
36{
37	struct irq_desc *desc = irq_to_desc((long)m->private);
38	unsigned long flags;
39	cpumask_var_t mask;
40
41	if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
42		return -ENOMEM;
43
44	raw_spin_lock_irqsave(&desc->lock, flags);
45	if (desc->affinity_hint)
46		cpumask_copy(mask, desc->affinity_hint);
47	raw_spin_unlock_irqrestore(&desc->lock, flags);
48
49	seq_cpumask(m, mask);
50	seq_putc(m, '\n');
51	free_cpumask_var(mask);
52
53	return 0;
54}
55
56#ifndef is_affinity_mask_valid
57#define is_affinity_mask_valid(val) 1
58#endif
59
60int no_irq_affinity;
61static ssize_t irq_affinity_proc_write(struct file *file,
62		const char __user *buffer, size_t count, loff_t *pos)
63{
64	unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data;
65	cpumask_var_t new_value;
66	int err;
67
68	if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity ||
69	    irq_balancing_disabled(irq))
70		return -EIO;
71
72	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
73		return -ENOMEM;
74
75	err = cpumask_parse_user(buffer, count, new_value);
76	if (err)
77		goto free_cpumask;
78
79	if (!is_affinity_mask_valid(new_value)) {
80		err = -EINVAL;
81		goto free_cpumask;
82	}
83
84	/*
85	 * Do not allow disabling IRQs completely - it's a too easy
86	 * way to make the system unusable accidentally :-) At least
87	 * one online CPU still has to be targeted.
88	 */
89	if (!cpumask_intersects(new_value, cpu_online_mask)) {
90		/* Special case for empty set - allow the architecture
91		   code to set default SMP affinity. */
92		err = irq_select_affinity_usr(irq) ? -EINVAL : count;
93	} else {
94		irq_set_affinity(irq, new_value);
95		err = count;
96	}
97
98free_cpumask:
99	free_cpumask_var(new_value);
100	return err;
101}
102
103static int irq_affinity_proc_open(struct inode *inode, struct file *file)
104{
105	return single_open(file, irq_affinity_proc_show, PDE(inode)->data);
106}
107
108static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file)
109{
110	return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data);
111}
112
113static const struct file_operations irq_affinity_proc_fops = {
114	.open		= irq_affinity_proc_open,
115	.read		= seq_read,
116	.llseek		= seq_lseek,
117	.release	= single_release,
118	.write		= irq_affinity_proc_write,
119};
120
121static const struct file_operations irq_affinity_hint_proc_fops = {
122	.open		= irq_affinity_hint_proc_open,
123	.read		= seq_read,
124	.llseek		= seq_lseek,
125	.release	= single_release,
126};
127
128static int default_affinity_show(struct seq_file *m, void *v)
129{
130	seq_cpumask(m, irq_default_affinity);
131	seq_putc(m, '\n');
132	return 0;
133}
134
135static ssize_t default_affinity_write(struct file *file,
136		const char __user *buffer, size_t count, loff_t *ppos)
137{
138	cpumask_var_t new_value;
139	int err;
140
141	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
142		return -ENOMEM;
143
144	err = cpumask_parse_user(buffer, count, new_value);
145	if (err)
146		goto out;
147
148	if (!is_affinity_mask_valid(new_value)) {
149		err = -EINVAL;
150		goto out;
151	}
152
153	/*
154	 * Do not allow disabling IRQs completely - it's a too easy
155	 * way to make the system unusable accidentally :-) At least
156	 * one online CPU still has to be targeted.
157	 */
158	if (!cpumask_intersects(new_value, cpu_online_mask)) {
159		err = -EINVAL;
160		goto out;
161	}
162
163	cpumask_copy(irq_default_affinity, new_value);
164	err = count;
165
166out:
167	free_cpumask_var(new_value);
168	return err;
169}
170
171static int default_affinity_open(struct inode *inode, struct file *file)
172{
173	return single_open(file, default_affinity_show, PDE(inode)->data);
174}
175
176static const struct file_operations default_affinity_proc_fops = {
177	.open		= default_affinity_open,
178	.read		= seq_read,
179	.llseek		= seq_lseek,
180	.release	= single_release,
181	.write		= default_affinity_write,
182};
183
184static int irq_node_proc_show(struct seq_file *m, void *v)
185{
186	struct irq_desc *desc = irq_to_desc((long) m->private);
187
188	seq_printf(m, "%d\n", desc->node);
189	return 0;
190}
191
192static int irq_node_proc_open(struct inode *inode, struct file *file)
193{
194	return single_open(file, irq_node_proc_show, PDE(inode)->data);
195}
196
197static const struct file_operations irq_node_proc_fops = {
198	.open		= irq_node_proc_open,
199	.read		= seq_read,
200	.llseek		= seq_lseek,
201	.release	= single_release,
202};
203#endif
204
205static int irq_spurious_proc_show(struct seq_file *m, void *v)
206{
207	struct irq_desc *desc = irq_to_desc((long) m->private);
208
209	seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n",
210		   desc->irq_count, desc->irqs_unhandled,
211		   jiffies_to_msecs(desc->last_unhandled));
212	return 0;
213}
214
215static int irq_spurious_proc_open(struct inode *inode, struct file *file)
216{
217	return single_open(file, irq_spurious_proc_show, PDE(inode)->data);
218}
219
220static const struct file_operations irq_spurious_proc_fops = {
221	.open		= irq_spurious_proc_open,
222	.read		= seq_read,
223	.llseek		= seq_lseek,
224	.release	= single_release,
225};
226
227#define MAX_NAMELEN 128
228
229static int name_unique(unsigned int irq, struct irqaction *new_action)
230{
231	struct irq_desc *desc = irq_to_desc(irq);
232	struct irqaction *action;
233	unsigned long flags;
234	int ret = 1;
235
236	raw_spin_lock_irqsave(&desc->lock, flags);
237	for (action = desc->action ; action; action = action->next) {
238		if ((action != new_action) && action->name &&
239				!strcmp(new_action->name, action->name)) {
240			ret = 0;
241			break;
242		}
243	}
244	raw_spin_unlock_irqrestore(&desc->lock, flags);
245	return ret;
246}
247
248void register_handler_proc(unsigned int irq, struct irqaction *action)
249{
250	char name [MAX_NAMELEN];
251	struct irq_desc *desc = irq_to_desc(irq);
252
253	if (!desc->dir || action->dir || !action->name ||
254					!name_unique(irq, action))
255		return;
256
257	memset(name, 0, MAX_NAMELEN);
258	snprintf(name, MAX_NAMELEN, "%s", action->name);
259
260	/* create /proc/irq/1234/handler/ */
261	action->dir = proc_mkdir(name, desc->dir);
262}
263
264#undef MAX_NAMELEN
265
266#define MAX_NAMELEN 10
267
268void register_irq_proc(unsigned int irq, struct irq_desc *desc)
269{
270	char name [MAX_NAMELEN];
271
272	if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir)
273		return;
274
275	memset(name, 0, MAX_NAMELEN);
276	sprintf(name, "%d", irq);
277
278	/* create /proc/irq/1234 */
279	desc->dir = proc_mkdir(name, root_irq_dir);
280	if (!desc->dir)
281		return;
282
283#ifdef CONFIG_SMP
284	/* create /proc/irq/<irq>/smp_affinity */
285	proc_create_data("smp_affinity", 0600, desc->dir,
286			 &irq_affinity_proc_fops, (void *)(long)irq);
287
288	/* create /proc/irq/<irq>/affinity_hint */
289	proc_create_data("affinity_hint", 0400, desc->dir,
290			 &irq_affinity_hint_proc_fops, (void *)(long)irq);
291
292	proc_create_data("node", 0444, desc->dir,
293			 &irq_node_proc_fops, (void *)(long)irq);
294#endif
295
296	proc_create_data("spurious", 0444, desc->dir,
297			 &irq_spurious_proc_fops, (void *)(long)irq);
298}
299
300#undef MAX_NAMELEN
301
302void unregister_handler_proc(unsigned int irq, struct irqaction *action)
303{
304	if (action->dir) {
305		struct irq_desc *desc = irq_to_desc(irq);
306
307		remove_proc_entry(action->dir->name, desc->dir);
308	}
309}
310
311static void register_default_affinity_proc(void)
312{
313#ifdef CONFIG_SMP
314	proc_create("irq/default_smp_affinity", 0600, NULL,
315		    &default_affinity_proc_fops);
316#endif
317}
318
319void init_irq_proc(void)
320{
321	unsigned int irq;
322	struct irq_desc *desc;
323
324	/* create /proc/irq */
325	root_irq_dir = proc_mkdir("irq", NULL);
326	if (!root_irq_dir)
327		return;
328
329	register_default_affinity_proc();
330
331	/*
332	 * Create entries for all existing IRQs.
333	 */
334	for_each_irq_desc(irq, desc) {
335		if (!desc)
336			continue;
337
338		register_irq_proc(irq, desc);
339	}
340}
341