diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2011-08-27 09:43:54 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2011-08-27 10:06:11 -0400 |
commit | 7b1bb388bc879ffcc6c69b567816d5c354afe42b (patch) | |
tree | 5a217fdfb0b5e5a327bdcd624506337c1ae1fe32 /kernel/irq/proc.c | |
parent | 7d754596756240fa918b94cd0c3011c77a638987 (diff) | |
parent | 02f8c6aee8df3cdc935e9bdd4f2d020306035dbe (diff) |
Merge 'Linux v3.0' into Litmus
Some notes:
* Litmus^RT scheduling class is the topmost scheduling class
(above stop_sched_class).
* scheduler_ipi() function (e.g., in smp_reschedule_interrupt())
may increase IPI latencies.
* Added path into schedule() to quickly re-evaluate scheduling
decision without becoming preemptive again. This used to be
a standard path before the removal of BKL.
Conflicts:
Makefile
arch/arm/kernel/calls.S
arch/arm/kernel/smp.c
arch/x86/include/asm/unistd_32.h
arch/x86/kernel/smp.c
arch/x86/kernel/syscall_table_32.S
include/linux/hrtimer.h
kernel/printk.c
kernel/sched.c
kernel/sched_fair.c
Diffstat (limited to 'kernel/irq/proc.c')
-rw-r--r-- | kernel/irq/proc.c | 169 |
1 files changed, 157 insertions, 12 deletions
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 09a2ee540bd2..4bd4faa6323a 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/proc_fs.h> | 11 | #include <linux/proc_fs.h> |
12 | #include <linux/seq_file.h> | 12 | #include <linux/seq_file.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/kernel_stat.h> | ||
14 | 15 | ||
15 | #include "internals.h" | 16 | #include "internals.h" |
16 | 17 | ||
@@ -18,16 +19,19 @@ static struct proc_dir_entry *root_irq_dir; | |||
18 | 19 | ||
19 | #ifdef CONFIG_SMP | 20 | #ifdef CONFIG_SMP |
20 | 21 | ||
21 | static int irq_affinity_proc_show(struct seq_file *m, void *v) | 22 | static int show_irq_affinity(int type, struct seq_file *m, void *v) |
22 | { | 23 | { |
23 | struct irq_desc *desc = irq_to_desc((long)m->private); | 24 | struct irq_desc *desc = irq_to_desc((long)m->private); |
24 | const struct cpumask *mask = desc->affinity; | 25 | const struct cpumask *mask = desc->irq_data.affinity; |
25 | 26 | ||
26 | #ifdef CONFIG_GENERIC_PENDING_IRQ | 27 | #ifdef CONFIG_GENERIC_PENDING_IRQ |
27 | if (desc->status & IRQ_MOVE_PENDING) | 28 | if (irqd_is_setaffinity_pending(&desc->irq_data)) |
28 | mask = desc->pending_mask; | 29 | mask = desc->pending_mask; |
29 | #endif | 30 | #endif |
30 | seq_cpumask(m, mask); | 31 | if (type) |
32 | seq_cpumask_list(m, mask); | ||
33 | else | ||
34 | seq_cpumask(m, mask); | ||
31 | seq_putc(m, '\n'); | 35 | seq_putc(m, '\n'); |
32 | return 0; | 36 | return 0; |
33 | } | 37 | } |
@@ -58,21 +62,34 @@ static int irq_affinity_hint_proc_show(struct seq_file *m, void *v) | |||
58 | #endif | 62 | #endif |
59 | 63 | ||
60 | int no_irq_affinity; | 64 | int no_irq_affinity; |
61 | static ssize_t irq_affinity_proc_write(struct file *file, | 65 | static int irq_affinity_proc_show(struct seq_file *m, void *v) |
66 | { | ||
67 | return show_irq_affinity(0, m, v); | ||
68 | } | ||
69 | |||
70 | static int irq_affinity_list_proc_show(struct seq_file *m, void *v) | ||
71 | { | ||
72 | return show_irq_affinity(1, m, v); | ||
73 | } | ||
74 | |||
75 | |||
76 | static ssize_t write_irq_affinity(int type, struct file *file, | ||
62 | const char __user *buffer, size_t count, loff_t *pos) | 77 | const char __user *buffer, size_t count, loff_t *pos) |
63 | { | 78 | { |
64 | unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data; | 79 | unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data; |
65 | cpumask_var_t new_value; | 80 | cpumask_var_t new_value; |
66 | int err; | 81 | int err; |
67 | 82 | ||
68 | if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity || | 83 | if (!irq_can_set_affinity(irq) || no_irq_affinity) |
69 | irq_balancing_disabled(irq)) | ||
70 | return -EIO; | 84 | return -EIO; |
71 | 85 | ||
72 | if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) | 86 | if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) |
73 | return -ENOMEM; | 87 | return -ENOMEM; |
74 | 88 | ||
75 | err = cpumask_parse_user(buffer, count, new_value); | 89 | if (type) |
90 | err = cpumask_parselist_user(buffer, count, new_value); | ||
91 | else | ||
92 | err = cpumask_parse_user(buffer, count, new_value); | ||
76 | if (err) | 93 | if (err) |
77 | goto free_cpumask; | 94 | goto free_cpumask; |
78 | 95 | ||
@@ -89,7 +106,7 @@ static ssize_t irq_affinity_proc_write(struct file *file, | |||
89 | if (!cpumask_intersects(new_value, cpu_online_mask)) { | 106 | if (!cpumask_intersects(new_value, cpu_online_mask)) { |
90 | /* Special case for empty set - allow the architecture | 107 | /* Special case for empty set - allow the architecture |
91 | code to set default SMP affinity. */ | 108 | code to set default SMP affinity. */ |
92 | err = irq_select_affinity_usr(irq) ? -EINVAL : count; | 109 | err = irq_select_affinity_usr(irq, new_value) ? -EINVAL : count; |
93 | } else { | 110 | } else { |
94 | irq_set_affinity(irq, new_value); | 111 | irq_set_affinity(irq, new_value); |
95 | err = count; | 112 | err = count; |
@@ -100,11 +117,28 @@ free_cpumask: | |||
100 | return err; | 117 | return err; |
101 | } | 118 | } |
102 | 119 | ||
120 | static ssize_t irq_affinity_proc_write(struct file *file, | ||
121 | const char __user *buffer, size_t count, loff_t *pos) | ||
122 | { | ||
123 | return write_irq_affinity(0, file, buffer, count, pos); | ||
124 | } | ||
125 | |||
126 | static ssize_t irq_affinity_list_proc_write(struct file *file, | ||
127 | const char __user *buffer, size_t count, loff_t *pos) | ||
128 | { | ||
129 | return write_irq_affinity(1, file, buffer, count, pos); | ||
130 | } | ||
131 | |||
103 | static int irq_affinity_proc_open(struct inode *inode, struct file *file) | 132 | static int irq_affinity_proc_open(struct inode *inode, struct file *file) |
104 | { | 133 | { |
105 | return single_open(file, irq_affinity_proc_show, PDE(inode)->data); | 134 | return single_open(file, irq_affinity_proc_show, PDE(inode)->data); |
106 | } | 135 | } |
107 | 136 | ||
137 | static int irq_affinity_list_proc_open(struct inode *inode, struct file *file) | ||
138 | { | ||
139 | return single_open(file, irq_affinity_list_proc_show, PDE(inode)->data); | ||
140 | } | ||
141 | |||
108 | static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file) | 142 | static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file) |
109 | { | 143 | { |
110 | return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data); | 144 | return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data); |
@@ -125,6 +159,14 @@ static const struct file_operations irq_affinity_hint_proc_fops = { | |||
125 | .release = single_release, | 159 | .release = single_release, |
126 | }; | 160 | }; |
127 | 161 | ||
162 | static const struct file_operations irq_affinity_list_proc_fops = { | ||
163 | .open = irq_affinity_list_proc_open, | ||
164 | .read = seq_read, | ||
165 | .llseek = seq_lseek, | ||
166 | .release = single_release, | ||
167 | .write = irq_affinity_list_proc_write, | ||
168 | }; | ||
169 | |||
128 | static int default_affinity_show(struct seq_file *m, void *v) | 170 | static int default_affinity_show(struct seq_file *m, void *v) |
129 | { | 171 | { |
130 | seq_cpumask(m, irq_default_affinity); | 172 | seq_cpumask(m, irq_default_affinity); |
@@ -185,7 +227,7 @@ static int irq_node_proc_show(struct seq_file *m, void *v) | |||
185 | { | 227 | { |
186 | struct irq_desc *desc = irq_to_desc((long) m->private); | 228 | struct irq_desc *desc = irq_to_desc((long) m->private); |
187 | 229 | ||
188 | seq_printf(m, "%d\n", desc->node); | 230 | seq_printf(m, "%d\n", desc->irq_data.node); |
189 | return 0; | 231 | return 0; |
190 | } | 232 | } |
191 | 233 | ||
@@ -214,7 +256,7 @@ static int irq_spurious_proc_show(struct seq_file *m, void *v) | |||
214 | 256 | ||
215 | static int irq_spurious_proc_open(struct inode *inode, struct file *file) | 257 | static int irq_spurious_proc_open(struct inode *inode, struct file *file) |
216 | { | 258 | { |
217 | return single_open(file, irq_spurious_proc_show, NULL); | 259 | return single_open(file, irq_spurious_proc_show, PDE(inode)->data); |
218 | } | 260 | } |
219 | 261 | ||
220 | static const struct file_operations irq_spurious_proc_fops = { | 262 | static const struct file_operations irq_spurious_proc_fops = { |
@@ -269,7 +311,7 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) | |||
269 | { | 311 | { |
270 | char name [MAX_NAMELEN]; | 312 | char name [MAX_NAMELEN]; |
271 | 313 | ||
272 | if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir) | 314 | if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir) |
273 | return; | 315 | return; |
274 | 316 | ||
275 | memset(name, 0, MAX_NAMELEN); | 317 | memset(name, 0, MAX_NAMELEN); |
@@ -289,6 +331,10 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) | |||
289 | proc_create_data("affinity_hint", 0400, desc->dir, | 331 | proc_create_data("affinity_hint", 0400, desc->dir, |
290 | &irq_affinity_hint_proc_fops, (void *)(long)irq); | 332 | &irq_affinity_hint_proc_fops, (void *)(long)irq); |
291 | 333 | ||
334 | /* create /proc/irq/<irq>/smp_affinity_list */ | ||
335 | proc_create_data("smp_affinity_list", 0600, desc->dir, | ||
336 | &irq_affinity_list_proc_fops, (void *)(long)irq); | ||
337 | |||
292 | proc_create_data("node", 0444, desc->dir, | 338 | proc_create_data("node", 0444, desc->dir, |
293 | &irq_node_proc_fops, (void *)(long)irq); | 339 | &irq_node_proc_fops, (void *)(long)irq); |
294 | #endif | 340 | #endif |
@@ -297,6 +343,25 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc) | |||
297 | &irq_spurious_proc_fops, (void *)(long)irq); | 343 | &irq_spurious_proc_fops, (void *)(long)irq); |
298 | } | 344 | } |
299 | 345 | ||
346 | void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) | ||
347 | { | ||
348 | char name [MAX_NAMELEN]; | ||
349 | |||
350 | if (!root_irq_dir || !desc->dir) | ||
351 | return; | ||
352 | #ifdef CONFIG_SMP | ||
353 | remove_proc_entry("smp_affinity", desc->dir); | ||
354 | remove_proc_entry("affinity_hint", desc->dir); | ||
355 | remove_proc_entry("smp_affinity_list", desc->dir); | ||
356 | remove_proc_entry("node", desc->dir); | ||
357 | #endif | ||
358 | remove_proc_entry("spurious", desc->dir); | ||
359 | |||
360 | memset(name, 0, MAX_NAMELEN); | ||
361 | sprintf(name, "%u", irq); | ||
362 | remove_proc_entry(name, root_irq_dir); | ||
363 | } | ||
364 | |||
300 | #undef MAX_NAMELEN | 365 | #undef MAX_NAMELEN |
301 | 366 | ||
302 | void unregister_handler_proc(unsigned int irq, struct irqaction *action) | 367 | void unregister_handler_proc(unsigned int irq, struct irqaction *action) |
@@ -339,3 +404,83 @@ void init_irq_proc(void) | |||
339 | } | 404 | } |
340 | } | 405 | } |
341 | 406 | ||
407 | #ifdef CONFIG_GENERIC_IRQ_SHOW | ||
408 | |||
409 | int __weak arch_show_interrupts(struct seq_file *p, int prec) | ||
410 | { | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | #ifndef ACTUAL_NR_IRQS | ||
415 | # define ACTUAL_NR_IRQS nr_irqs | ||
416 | #endif | ||
417 | |||
418 | int show_interrupts(struct seq_file *p, void *v) | ||
419 | { | ||
420 | static int prec; | ||
421 | |||
422 | unsigned long flags, any_count = 0; | ||
423 | int i = *(loff_t *) v, j; | ||
424 | struct irqaction *action; | ||
425 | struct irq_desc *desc; | ||
426 | |||
427 | if (i > ACTUAL_NR_IRQS) | ||
428 | return 0; | ||
429 | |||
430 | if (i == ACTUAL_NR_IRQS) | ||
431 | return arch_show_interrupts(p, prec); | ||
432 | |||
433 | /* print header and calculate the width of the first column */ | ||
434 | if (i == 0) { | ||
435 | for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec) | ||
436 | j *= 10; | ||
437 | |||
438 | seq_printf(p, "%*s", prec + 8, ""); | ||
439 | for_each_online_cpu(j) | ||
440 | seq_printf(p, "CPU%-8d", j); | ||
441 | seq_putc(p, '\n'); | ||
442 | } | ||
443 | |||
444 | desc = irq_to_desc(i); | ||
445 | if (!desc) | ||
446 | return 0; | ||
447 | |||
448 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
449 | for_each_online_cpu(j) | ||
450 | any_count |= kstat_irqs_cpu(i, j); | ||
451 | action = desc->action; | ||
452 | if (!action && !any_count) | ||
453 | goto out; | ||
454 | |||
455 | seq_printf(p, "%*d: ", prec, i); | ||
456 | for_each_online_cpu(j) | ||
457 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
458 | |||
459 | if (desc->irq_data.chip) { | ||
460 | if (desc->irq_data.chip->irq_print_chip) | ||
461 | desc->irq_data.chip->irq_print_chip(&desc->irq_data, p); | ||
462 | else if (desc->irq_data.chip->name) | ||
463 | seq_printf(p, " %8s", desc->irq_data.chip->name); | ||
464 | else | ||
465 | seq_printf(p, " %8s", "-"); | ||
466 | } else { | ||
467 | seq_printf(p, " %8s", "None"); | ||
468 | } | ||
469 | #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL | ||
470 | seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); | ||
471 | #endif | ||
472 | if (desc->name) | ||
473 | seq_printf(p, "-%-8s", desc->name); | ||
474 | |||
475 | if (action) { | ||
476 | seq_printf(p, " %s", action->name); | ||
477 | while ((action = action->next) != NULL) | ||
478 | seq_printf(p, ", %s", action->name); | ||
479 | } | ||
480 | |||
481 | seq_putc(p, '\n'); | ||
482 | out: | ||
483 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
484 | return 0; | ||
485 | } | ||
486 | #endif | ||