proc.c 9.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 * linux/kernel/irq/proc.c
 *
 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
 *
 * This file contains the /proc/irq/ handling code.
 */

#include <linux/irq.h>
10
#include <linux/gfp.h>
L
Linus Torvalds 已提交
11
#include <linux/proc_fs.h>
12
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
13
#include <linux/interrupt.h>
14
#include <linux/kernel_stat.h>
L
Linus Torvalds 已提交
15

A
Adrian Bunk 已提交
16 17
#include "internals.h"

18
static struct proc_dir_entry *root_irq_dir;
L
Linus Torvalds 已提交
19 20 21

#ifdef CONFIG_SMP

22
static int irq_affinity_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
23
{
24
	struct irq_desc *desc = irq_to_desc((long)m->private);
25
	const struct cpumask *mask = desc->irq_data.affinity;
26 27

#ifdef CONFIG_GENERIC_PENDING_IRQ
28
	if (irqd_is_setaffinity_pending(&desc->irq_data))
29
		mask = desc->pending_mask;
30
#endif
31 32 33
	seq_cpumask(m, mask);
	seq_putc(m, '\n');
	return 0;
L
Linus Torvalds 已提交
34 35
}

36 37 38 39 40 41
static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
{
	struct irq_desc *desc = irq_to_desc((long)m->private);
	unsigned long flags;
	cpumask_var_t mask;

42
	if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
43 44 45 46 47 48 49 50 51 52 53 54 55 56
		return -ENOMEM;

	raw_spin_lock_irqsave(&desc->lock, flags);
	if (desc->affinity_hint)
		cpumask_copy(mask, desc->affinity_hint);
	raw_spin_unlock_irqrestore(&desc->lock, flags);

	seq_cpumask(m, mask);
	seq_putc(m, '\n');
	free_cpumask_var(mask);

	return 0;
}

57 58 59 60
#ifndef is_affinity_mask_valid
#define is_affinity_mask_valid(val) 1
#endif

L
Linus Torvalds 已提交
61
int no_irq_affinity;
62 63
static ssize_t irq_affinity_proc_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *pos)
L
Linus Torvalds 已提交
64
{
65
	unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data;
66
	cpumask_var_t new_value;
67
	int err;
L
Linus Torvalds 已提交
68

69
	if (!irq_can_set_affinity(irq) || no_irq_affinity)
L
Linus Torvalds 已提交
70 71
		return -EIO;

72 73 74 75
	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
		return -ENOMEM;

	err = cpumask_parse_user(buffer, count, new_value);
L
Linus Torvalds 已提交
76
	if (err)
77
		goto free_cpumask;
L
Linus Torvalds 已提交
78

79
	if (!is_affinity_mask_valid(new_value)) {
80 81 82
		err = -EINVAL;
		goto free_cpumask;
	}
83

L
Linus Torvalds 已提交
84 85 86 87 88
	/*
	 * Do not allow disabling IRQs completely - it's a too easy
	 * way to make the system unusable accidentally :-) At least
	 * one online CPU still has to be targeted.
	 */
89
	if (!cpumask_intersects(new_value, cpu_online_mask)) {
90 91
		/* Special case for empty set - allow the architecture
		   code to set default SMP affinity. */
92
		err = irq_select_affinity_usr(irq, new_value) ? -EINVAL : count;
93 94 95 96 97 98 99 100
	} else {
		irq_set_affinity(irq, new_value);
		err = count;
	}

free_cpumask:
	free_cpumask_var(new_value);
	return err;
L
Linus Torvalds 已提交
101 102
}

103
static 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
}

108 109 110 111 112
static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data);
}

113 114 115 116 117 118 119 120
static const struct file_operations irq_affinity_proc_fops = {
	.open		= irq_affinity_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= irq_affinity_proc_write,
};

121 122 123 124 125 126 127
static const struct file_operations irq_affinity_hint_proc_fops = {
	.open		= irq_affinity_hint_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

128 129
static int default_affinity_show(struct seq_file *m, void *v)
{
R
Rusty Russell 已提交
130
	seq_cpumask(m, irq_default_affinity);
131 132 133 134 135 136
	seq_putc(m, '\n');
	return 0;
}

static ssize_t default_affinity_write(struct file *file,
		const char __user *buffer, size_t count, loff_t *ppos)
137
{
R
Rusty Russell 已提交
138
	cpumask_var_t new_value;
139
	int err;
140

R
Rusty Russell 已提交
141 142 143 144
	if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
		return -ENOMEM;

	err = cpumask_parse_user(buffer, count, new_value);
145
	if (err)
R
Rusty Russell 已提交
146
		goto out;
147

R
Rusty Russell 已提交
148 149 150 151
	if (!is_affinity_mask_valid(new_value)) {
		err = -EINVAL;
		goto out;
	}
152 153 154 155 156 157

	/*
	 * Do not allow disabling IRQs completely - it's a too easy
	 * way to make the system unusable accidentally :-) At least
	 * one online CPU still has to be targeted.
	 */
R
Rusty Russell 已提交
158 159 160 161
	if (!cpumask_intersects(new_value, cpu_online_mask)) {
		err = -EINVAL;
		goto out;
	}
162

R
Rusty Russell 已提交
163 164
	cpumask_copy(irq_default_affinity, new_value);
	err = count;
165

R
Rusty Russell 已提交
166 167 168
out:
	free_cpumask_var(new_value);
	return err;
169
}
170 171 172

static int default_affinity_open(struct inode *inode, struct file *file)
{
173
	return single_open(file, default_affinity_show, PDE(inode)->data);
174 175 176 177 178 179 180 181 182
}

static const struct file_operations default_affinity_proc_fops = {
	.open		= default_affinity_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.write		= default_affinity_write,
};
183 184 185 186 187

static int irq_node_proc_show(struct seq_file *m, void *v)
{
	struct irq_desc *desc = irq_to_desc((long) m->private);

188
	seq_printf(m, "%d\n", desc->irq_data.node);
189 190 191 192 193 194 195 196 197 198 199 200 201 202
	return 0;
}

static int irq_node_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, irq_node_proc_show, PDE(inode)->data);
}

static const struct file_operations irq_node_proc_fops = {
	.open		= irq_node_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};
L
Linus Torvalds 已提交
203 204
#endif

205
static int irq_spurious_proc_show(struct seq_file *m, void *v)
206
{
207 208 209 210 211 212 213 214 215 216
	struct irq_desc *desc = irq_to_desc((long) m->private);

	seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n",
		   desc->irq_count, desc->irqs_unhandled,
		   jiffies_to_msecs(desc->last_unhandled));
	return 0;
}

static int irq_spurious_proc_open(struct inode *inode, struct file *file)
{
217
	return single_open(file, irq_spurious_proc_show, PDE(inode)->data);
218 219
}

220 221 222 223 224 225 226
static const struct file_operations irq_spurious_proc_fops = {
	.open		= irq_spurious_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

L
Linus Torvalds 已提交
227 228 229 230
#define MAX_NAMELEN 128

static int name_unique(unsigned int irq, struct irqaction *new_action)
{
231
	struct irq_desc *desc = irq_to_desc(irq);
L
Linus Torvalds 已提交
232
	struct irqaction *action;
233 234
	unsigned long flags;
	int ret = 1;
L
Linus Torvalds 已提交
235

236
	raw_spin_lock_irqsave(&desc->lock, flags);
237
	for (action = desc->action ; action; action = action->next) {
L
Linus Torvalds 已提交
238
		if ((action != new_action) && action->name &&
239 240 241 242 243
				!strcmp(new_action->name, action->name)) {
			ret = 0;
			break;
		}
	}
244
	raw_spin_unlock_irqrestore(&desc->lock, flags);
245
	return ret;
L
Linus Torvalds 已提交
246 247 248 249 250
}

void register_handler_proc(unsigned int irq, struct irqaction *action)
{
	char name [MAX_NAMELEN];
251
	struct irq_desc *desc = irq_to_desc(irq);
L
Linus Torvalds 已提交
252

253
	if (!desc->dir || action->dir || !action->name ||
L
Linus Torvalds 已提交
254 255 256 257 258 259 260
					!name_unique(irq, action))
		return;

	memset(name, 0, MAX_NAMELEN);
	snprintf(name, MAX_NAMELEN, "%s", action->name);

	/* create /proc/irq/1234/handler/ */
261
	action->dir = proc_mkdir(name, desc->dir);
L
Linus Torvalds 已提交
262 263 264 265 266 267
}

#undef MAX_NAMELEN

#define MAX_NAMELEN 10

268
void register_irq_proc(unsigned int irq, struct irq_desc *desc)
L
Linus Torvalds 已提交
269 270 271
{
	char name [MAX_NAMELEN];

272
	if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir)
L
Linus Torvalds 已提交
273 274 275 276 277 278
		return;

	memset(name, 0, MAX_NAMELEN);
	sprintf(name, "%d", irq);

	/* create /proc/irq/1234 */
279
	desc->dir = proc_mkdir(name, root_irq_dir);
280 281
	if (!desc->dir)
		return;
L
Linus Torvalds 已提交
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 289 290 291
	/* create /proc/irq/<irq>/affinity_hint */
	proc_create_data("affinity_hint", 0400, desc->dir,
			 &irq_affinity_hint_proc_fops, (void *)(long)irq);

292 293
	proc_create_data("node", 0444, desc->dir,
			 &irq_node_proc_fops, (void *)(long)irq);
L
Linus Torvalds 已提交
294
#endif
295

296 297
	proc_create_data("spurious", 0444, desc->dir,
			 &irq_spurious_proc_fops, (void *)(long)irq);
L
Linus Torvalds 已提交
298 299
}

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
{
	char name [MAX_NAMELEN];

	if (!root_irq_dir || !desc->dir)
		return;
#ifdef CONFIG_SMP
	remove_proc_entry("smp_affinity", desc->dir);
	remove_proc_entry("affinity_hint", desc->dir);
	remove_proc_entry("node", desc->dir);
#endif
	remove_proc_entry("spurious", desc->dir);

	memset(name, 0, MAX_NAMELEN);
	sprintf(name, "%u", irq);
	remove_proc_entry(name, root_irq_dir);
}

L
Linus Torvalds 已提交
318 319 320 321
#undef MAX_NAMELEN

void unregister_handler_proc(unsigned int irq, struct irqaction *action)
{
322 323
	if (action->dir) {
		struct irq_desc *desc = irq_to_desc(irq);
324

325 326
		remove_proc_entry(action->dir->name, desc->dir);
	}
L
Linus Torvalds 已提交
327 328
}

R
roel kluin 已提交
329
static void register_default_affinity_proc(void)
330 331
{
#ifdef CONFIG_SMP
332 333
	proc_create("irq/default_smp_affinity", 0600, NULL,
		    &default_affinity_proc_fops);
334 335 336
#endif
}

L
Linus Torvalds 已提交
337 338
void init_irq_proc(void)
{
339 340
	unsigned int irq;
	struct irq_desc *desc;
L
Linus Torvalds 已提交
341 342 343 344 345 346

	/* create /proc/irq */
	root_irq_dir = proc_mkdir("irq", NULL);
	if (!root_irq_dir)
		return;

347 348
	register_default_affinity_proc();

L
Linus Torvalds 已提交
349 350 351
	/*
	 * Create entries for all existing IRQs.
	 */
352 353 354 355
	for_each_irq_desc(irq, desc) {
		if (!desc)
			continue;

356
		register_irq_proc(irq, desc);
357
	}
L
Linus Torvalds 已提交
358 359
}

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
#ifdef CONFIG_GENERIC_IRQ_SHOW

int __weak arch_show_interrupts(struct seq_file *p, int prec)
{
	return 0;
}

int show_interrupts(struct seq_file *p, void *v)
{
	static int prec;

	unsigned long flags, any_count = 0;
	int i = *(loff_t *) v, j;
	struct irqaction *action;
	struct irq_desc *desc;

	if (i > nr_irqs)
		return 0;

	if (i == nr_irqs)
		return arch_show_interrupts(p, prec);

	/* print header and calculate the width of the first column */
	if (i == 0) {
		for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec)
			j *= 10;

		seq_printf(p, "%*s", prec + 8, "");
		for_each_online_cpu(j)
			seq_printf(p, "CPU%-8d", j);
		seq_putc(p, '\n');
	}

	desc = irq_to_desc(i);
	if (!desc)
		return 0;

	raw_spin_lock_irqsave(&desc->lock, flags);
	for_each_online_cpu(j)
		any_count |= kstat_irqs_cpu(i, j);
	action = desc->action;
	if (!action && !any_count)
		goto out;

	seq_printf(p, "%*d: ", prec, i);
	for_each_online_cpu(j)
		seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
	seq_printf(p, " %8s", desc->irq_data.chip->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');
out:
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	return 0;
}
#endif