aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-15 07:46:29 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-15 07:46:29 -0400
commitb2aaf8f74cdc84a9182f6cabf198b7763bcb9d40 (patch)
tree53ccb1c2c14751fe69cf93102e76e97021f6df07 /kernel/irq
parent4f962d4d65923d7b722192e729840cfb79af0a5a (diff)
parent278429cff8809958d25415ba0ed32b59866ab1a8 (diff)
Merge branch 'linus' into stackprotector
Conflicts: arch/x86/kernel/Makefile include/asm-x86/pda.h
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/chip.c12
-rw-r--r--kernel/irq/manage.c149
-rw-r--r--kernel/irq/proc.c113
3 files changed, 195 insertions, 79 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 964964baefa2..3cd441ebf5d2 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -28,8 +28,7 @@ void dynamic_irq_init(unsigned int irq)
28 unsigned long flags; 28 unsigned long flags;
29 29
30 if (irq >= NR_IRQS) { 30 if (irq >= NR_IRQS) {
31 printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq); 31 WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
32 WARN_ON(1);
33 return; 32 return;
34 } 33 }
35 34
@@ -62,8 +61,7 @@ void dynamic_irq_cleanup(unsigned int irq)
62 unsigned long flags; 61 unsigned long flags;
63 62
64 if (irq >= NR_IRQS) { 63 if (irq >= NR_IRQS) {
65 printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq); 64 WARN(1, KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
66 WARN_ON(1);
67 return; 65 return;
68 } 66 }
69 67
@@ -71,9 +69,8 @@ void dynamic_irq_cleanup(unsigned int irq)
71 spin_lock_irqsave(&desc->lock, flags); 69 spin_lock_irqsave(&desc->lock, flags);
72 if (desc->action) { 70 if (desc->action) {
73 spin_unlock_irqrestore(&desc->lock, flags); 71 spin_unlock_irqrestore(&desc->lock, flags);
74 printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n", 72 WARN(1, KERN_ERR "Destroying IRQ%d without calling free_irq\n",
75 irq); 73 irq);
76 WARN_ON(1);
77 return; 74 return;
78 } 75 }
79 desc->msi_desc = NULL; 76 desc->msi_desc = NULL;
@@ -96,8 +93,7 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
96 unsigned long flags; 93 unsigned long flags;
97 94
98 if (irq >= NR_IRQS) { 95 if (irq >= NR_IRQS) {
99 printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); 96 WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
100 WARN_ON(1);
101 return -EINVAL; 97 return -EINVAL;
102 } 98 }
103 99
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 46d6611a33bb..60c49e324390 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -17,6 +17,8 @@
17 17
18#ifdef CONFIG_SMP 18#ifdef CONFIG_SMP
19 19
20cpumask_t irq_default_affinity = CPU_MASK_ALL;
21
20/** 22/**
21 * synchronize_irq - wait for pending IRQ handlers (on other CPUs) 23 * synchronize_irq - wait for pending IRQ handlers (on other CPUs)
22 * @irq: interrupt number to wait for 24 * @irq: interrupt number to wait for
@@ -87,7 +89,14 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
87 set_balance_irq_affinity(irq, cpumask); 89 set_balance_irq_affinity(irq, cpumask);
88 90
89#ifdef CONFIG_GENERIC_PENDING_IRQ 91#ifdef CONFIG_GENERIC_PENDING_IRQ
90 set_pending_irq(irq, cpumask); 92 if (desc->status & IRQ_MOVE_PCNTXT) {
93 unsigned long flags;
94
95 spin_lock_irqsave(&desc->lock, flags);
96 desc->chip->set_affinity(irq, cpumask);
97 spin_unlock_irqrestore(&desc->lock, flags);
98 } else
99 set_pending_irq(irq, cpumask);
91#else 100#else
92 desc->affinity = cpumask; 101 desc->affinity = cpumask;
93 desc->chip->set_affinity(irq, cpumask); 102 desc->chip->set_affinity(irq, cpumask);
@@ -95,6 +104,27 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
95 return 0; 104 return 0;
96} 105}
97 106
107#ifndef CONFIG_AUTO_IRQ_AFFINITY
108/*
109 * Generic version of the affinity autoselector.
110 */
111int irq_select_affinity(unsigned int irq)
112{
113 cpumask_t mask;
114
115 if (!irq_can_set_affinity(irq))
116 return 0;
117
118 cpus_and(mask, cpu_online_map, irq_default_affinity);
119
120 irq_desc[irq].affinity = mask;
121 irq_desc[irq].chip->set_affinity(irq, mask);
122
123 set_balance_irq_affinity(irq, mask);
124 return 0;
125}
126#endif
127
98#endif 128#endif
99 129
100/** 130/**
@@ -154,8 +184,7 @@ static void __enable_irq(struct irq_desc *desc, unsigned int irq)
154{ 184{
155 switch (desc->depth) { 185 switch (desc->depth) {
156 case 0: 186 case 0:
157 printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); 187 WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
158 WARN_ON(1);
159 break; 188 break;
160 case 1: { 189 case 1: {
161 unsigned int status = desc->status & ~IRQ_DISABLED; 190 unsigned int status = desc->status & ~IRQ_DISABLED;
@@ -194,6 +223,17 @@ void enable_irq(unsigned int irq)
194} 223}
195EXPORT_SYMBOL(enable_irq); 224EXPORT_SYMBOL(enable_irq);
196 225
226int set_irq_wake_real(unsigned int irq, unsigned int on)
227{
228 struct irq_desc *desc = irq_desc + irq;
229 int ret = -ENXIO;
230
231 if (desc->chip->set_wake)
232 ret = desc->chip->set_wake(irq, on);
233
234 return ret;
235}
236
197/** 237/**
198 * set_irq_wake - control irq power management wakeup 238 * set_irq_wake - control irq power management wakeup
199 * @irq: interrupt to control 239 * @irq: interrupt to control
@@ -210,30 +250,32 @@ int set_irq_wake(unsigned int irq, unsigned int on)
210{ 250{
211 struct irq_desc *desc = irq_desc + irq; 251 struct irq_desc *desc = irq_desc + irq;
212 unsigned long flags; 252 unsigned long flags;
213 int ret = -ENXIO; 253 int ret = 0;
214 int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake;
215 254
216 /* wakeup-capable irqs can be shared between drivers that 255 /* wakeup-capable irqs can be shared between drivers that
217 * don't need to have the same sleep mode behaviors. 256 * don't need to have the same sleep mode behaviors.
218 */ 257 */
219 spin_lock_irqsave(&desc->lock, flags); 258 spin_lock_irqsave(&desc->lock, flags);
220 if (on) { 259 if (on) {
221 if (desc->wake_depth++ == 0) 260 if (desc->wake_depth++ == 0) {
222 desc->status |= IRQ_WAKEUP; 261 ret = set_irq_wake_real(irq, on);
223 else 262 if (ret)
224 set_wake = NULL; 263 desc->wake_depth = 0;
264 else
265 desc->status |= IRQ_WAKEUP;
266 }
225 } else { 267 } else {
226 if (desc->wake_depth == 0) { 268 if (desc->wake_depth == 0) {
227 printk(KERN_WARNING "Unbalanced IRQ %d " 269 WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
228 "wake disable\n", irq); 270 } else if (--desc->wake_depth == 0) {
229 WARN_ON(1); 271 ret = set_irq_wake_real(irq, on);
230 } else if (--desc->wake_depth == 0) 272 if (ret)
231 desc->status &= ~IRQ_WAKEUP; 273 desc->wake_depth = 1;
232 else 274 else
233 set_wake = NULL; 275 desc->status &= ~IRQ_WAKEUP;
276 }
234 } 277 }
235 if (set_wake) 278
236 ret = desc->chip->set_wake(irq, on);
237 spin_unlock_irqrestore(&desc->lock, flags); 279 spin_unlock_irqrestore(&desc->lock, flags);
238 return ret; 280 return ret;
239} 281}
@@ -270,6 +312,31 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
270 desc->handle_irq = NULL; 312 desc->handle_irq = NULL;
271} 313}
272 314
315static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
316 unsigned long flags)
317{
318 int ret;
319
320 if (!chip || !chip->set_type) {
321 /*
322 * IRQF_TRIGGER_* but the PIC does not support multiple
323 * flow-types?
324 */
325 pr_warning("No set_type function for IRQ %d (%s)\n", irq,
326 chip ? (chip->name ? : "unknown") : "unknown");
327 return 0;
328 }
329
330 ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK);
331
332 if (ret)
333 pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
334 (int)(flags & IRQF_TRIGGER_MASK),
335 irq, chip->set_type);
336
337 return ret;
338}
339
273/* 340/*
274 * Internal function to register an irqaction - typically used to 341 * Internal function to register an irqaction - typically used to
275 * allocate special interrupts that are part of the architecture. 342 * allocate special interrupts that are part of the architecture.
@@ -281,6 +348,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
281 const char *old_name = NULL; 348 const char *old_name = NULL;
282 unsigned long flags; 349 unsigned long flags;
283 int shared = 0; 350 int shared = 0;
351 int ret;
284 352
285 if (irq >= NR_IRQS) 353 if (irq >= NR_IRQS)
286 return -EINVAL; 354 return -EINVAL;
@@ -338,36 +406,23 @@ int setup_irq(unsigned int irq, struct irqaction *new)
338 shared = 1; 406 shared = 1;
339 } 407 }
340 408
341 *p = new;
342
343 /* Exclude IRQ from balancing */
344 if (new->flags & IRQF_NOBALANCING)
345 desc->status |= IRQ_NO_BALANCING;
346
347 if (!shared) { 409 if (!shared) {
348 irq_chip_set_defaults(desc->chip); 410 irq_chip_set_defaults(desc->chip);
349 411
350#if defined(CONFIG_IRQ_PER_CPU)
351 if (new->flags & IRQF_PERCPU)
352 desc->status |= IRQ_PER_CPU;
353#endif
354
355 /* Setup the type (level, edge polarity) if configured: */ 412 /* Setup the type (level, edge polarity) if configured: */
356 if (new->flags & IRQF_TRIGGER_MASK) { 413 if (new->flags & IRQF_TRIGGER_MASK) {
357 if (desc->chip && desc->chip->set_type) 414 ret = __irq_set_trigger(desc->chip, irq, new->flags);
358 desc->chip->set_type(irq, 415
359 new->flags & IRQF_TRIGGER_MASK); 416 if (ret) {
360 else 417 spin_unlock_irqrestore(&desc->lock, flags);
361 /* 418 return ret;
362 * IRQF_TRIGGER_* but the PIC does not support 419 }
363 * multiple flow-types?
364 */
365 printk(KERN_WARNING "No IRQF_TRIGGER set_type "
366 "function for IRQ %d (%s)\n", irq,
367 desc->chip ? desc->chip->name :
368 "unknown");
369 } else 420 } else
370 compat_irq_chip_set_default_handler(desc); 421 compat_irq_chip_set_default_handler(desc);
422#if defined(CONFIG_IRQ_PER_CPU)
423 if (new->flags & IRQF_PERCPU)
424 desc->status |= IRQ_PER_CPU;
425#endif
371 426
372 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | 427 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
373 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); 428 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
@@ -382,7 +437,17 @@ int setup_irq(unsigned int irq, struct irqaction *new)
382 } else 437 } else
383 /* Undo nested disables: */ 438 /* Undo nested disables: */
384 desc->depth = 1; 439 desc->depth = 1;
440
441 /* Set default affinity mask once everything is setup */
442 irq_select_affinity(irq);
385 } 443 }
444
445 *p = new;
446
447 /* Exclude IRQ from balancing */
448 if (new->flags & IRQF_NOBALANCING)
449 desc->status |= IRQ_NO_BALANCING;
450
386 /* Reset broken irq detection when installing new handler */ 451 /* Reset broken irq detection when installing new handler */
387 desc->irq_count = 0; 452 desc->irq_count = 0;
388 desc->irqs_unhandled = 0; 453 desc->irqs_unhandled = 0;
@@ -571,8 +636,6 @@ int request_irq(unsigned int irq, irq_handler_t handler,
571 action->next = NULL; 636 action->next = NULL;
572 action->dev_id = dev_id; 637 action->dev_id = dev_id;
573 638
574 select_smp_affinity(irq);
575
576#ifdef CONFIG_DEBUG_SHIRQ 639#ifdef CONFIG_DEBUG_SHIRQ
577 if (irqflags & IRQF_SHARED) { 640 if (irqflags & IRQF_SHARED) {
578 /* 641 /*
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index c2f2ccb0549a..a09dd29c2fd7 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -8,6 +8,7 @@
8 8
9#include <linux/irq.h> 9#include <linux/irq.h>
10#include <linux/proc_fs.h> 10#include <linux/proc_fs.h>
11#include <linux/seq_file.h>
11#include <linux/interrupt.h> 12#include <linux/interrupt.h>
12 13
13#include "internals.h" 14#include "internals.h"
@@ -16,23 +17,18 @@ static struct proc_dir_entry *root_irq_dir;
16 17
17#ifdef CONFIG_SMP 18#ifdef CONFIG_SMP
18 19
19static int irq_affinity_read_proc(char *page, char **start, off_t off, 20static int irq_affinity_proc_show(struct seq_file *m, void *v)
20 int count, int *eof, void *data)
21{ 21{
22 struct irq_desc *desc = irq_desc + (long)data; 22 struct irq_desc *desc = irq_desc + (long)m->private;
23 cpumask_t *mask = &desc->affinity; 23 cpumask_t *mask = &desc->affinity;
24 int len;
25 24
26#ifdef CONFIG_GENERIC_PENDING_IRQ 25#ifdef CONFIG_GENERIC_PENDING_IRQ
27 if (desc->status & IRQ_MOVE_PENDING) 26 if (desc->status & IRQ_MOVE_PENDING)
28 mask = &desc->pending_mask; 27 mask = &desc->pending_mask;
29#endif 28#endif
30 len = cpumask_scnprintf(page, count, *mask); 29 seq_cpumask(m, mask);
31 30 seq_putc(m, '\n');
32 if (count - len < 2) 31 return 0;
33 return -EINVAL;
34 len += sprintf(page + len, "\n");
35 return len;
36} 32}
37 33
38#ifndef is_affinity_mask_valid 34#ifndef is_affinity_mask_valid
@@ -40,11 +36,12 @@ static int irq_affinity_read_proc(char *page, char **start, off_t off,
40#endif 36#endif
41 37
42int no_irq_affinity; 38int no_irq_affinity;
43static int irq_affinity_write_proc(struct file *file, const char __user *buffer, 39static ssize_t irq_affinity_proc_write(struct file *file,
44 unsigned long count, void *data) 40 const char __user *buffer, size_t count, loff_t *pos)
45{ 41{
46 unsigned int irq = (int)(long)data, full_count = count, err; 42 unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data;
47 cpumask_t new_value, tmp; 43 cpumask_t new_value;
44 int err;
48 45
49 if (!irq_desc[irq].chip->set_affinity || no_irq_affinity || 46 if (!irq_desc[irq].chip->set_affinity || no_irq_affinity ||
50 irq_balancing_disabled(irq)) 47 irq_balancing_disabled(irq))
@@ -62,17 +59,74 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
62 * way to make the system unusable accidentally :-) At least 59 * way to make the system unusable accidentally :-) At least
63 * one online CPU still has to be targeted. 60 * one online CPU still has to be targeted.
64 */ 61 */
65 cpus_and(tmp, new_value, cpu_online_map); 62 if (!cpus_intersects(new_value, cpu_online_map))
66 if (cpus_empty(tmp))
67 /* Special case for empty set - allow the architecture 63 /* Special case for empty set - allow the architecture
68 code to set default SMP affinity. */ 64 code to set default SMP affinity. */
69 return select_smp_affinity(irq) ? -EINVAL : full_count; 65 return irq_select_affinity(irq) ? -EINVAL : count;
70 66
71 irq_set_affinity(irq, new_value); 67 irq_set_affinity(irq, new_value);
72 68
73 return full_count; 69 return count;
70}
71
72static int irq_affinity_proc_open(struct inode *inode, struct file *file)
73{
74 return single_open(file, irq_affinity_proc_show, PDE(inode)->data);
75}
76
77static const struct file_operations irq_affinity_proc_fops = {
78 .open = irq_affinity_proc_open,
79 .read = seq_read,
80 .llseek = seq_lseek,
81 .release = single_release,
82 .write = irq_affinity_proc_write,
83};
84
85static int default_affinity_show(struct seq_file *m, void *v)
86{
87 seq_cpumask(m, &irq_default_affinity);
88 seq_putc(m, '\n');
89 return 0;
90}
91
92static ssize_t default_affinity_write(struct file *file,
93 const char __user *buffer, size_t count, loff_t *ppos)
94{
95 cpumask_t new_value;
96 int err;
97
98 err = cpumask_parse_user(buffer, count, new_value);
99 if (err)
100 return err;
101
102 if (!is_affinity_mask_valid(new_value))
103 return -EINVAL;
104
105 /*
106 * Do not allow disabling IRQs completely - it's a too easy
107 * way to make the system unusable accidentally :-) At least
108 * one online CPU still has to be targeted.
109 */
110 if (!cpus_intersects(new_value, cpu_online_map))
111 return -EINVAL;
112
113 irq_default_affinity = new_value;
114
115 return count;
116}
117
118static int default_affinity_open(struct inode *inode, struct file *file)
119{
120 return single_open(file, default_affinity_show, NULL);
74} 121}
75 122
123static const struct file_operations default_affinity_proc_fops = {
124 .open = default_affinity_open,
125 .read = seq_read,
126 .llseek = seq_lseek,
127 .release = single_release,
128 .write = default_affinity_write,
129};
76#endif 130#endif
77 131
78static int irq_spurious_read(char *page, char **start, off_t off, 132static int irq_spurious_read(char *page, char **start, off_t off,
@@ -144,16 +198,9 @@ void register_irq_proc(unsigned int irq)
144 irq_desc[irq].dir = proc_mkdir(name, root_irq_dir); 198 irq_desc[irq].dir = proc_mkdir(name, root_irq_dir);
145 199
146#ifdef CONFIG_SMP 200#ifdef CONFIG_SMP
147 { 201 /* create /proc/irq/<irq>/smp_affinity */
148 /* create /proc/irq/<irq>/smp_affinity */ 202 proc_create_data("smp_affinity", 0600, irq_desc[irq].dir,
149 entry = create_proc_entry("smp_affinity", 0600, irq_desc[irq].dir); 203 &irq_affinity_proc_fops, (void *)(long)irq);
150
151 if (entry) {
152 entry->data = (void *)(long)irq;
153 entry->read_proc = irq_affinity_read_proc;
154 entry->write_proc = irq_affinity_write_proc;
155 }
156 }
157#endif 204#endif
158 205
159 entry = create_proc_entry("spurious", 0444, irq_desc[irq].dir); 206 entry = create_proc_entry("spurious", 0444, irq_desc[irq].dir);
@@ -171,6 +218,14 @@ void unregister_handler_proc(unsigned int irq, struct irqaction *action)
171 remove_proc_entry(action->dir->name, irq_desc[irq].dir); 218 remove_proc_entry(action->dir->name, irq_desc[irq].dir);
172} 219}
173 220
221void register_default_affinity_proc(void)
222{
223#ifdef CONFIG_SMP
224 proc_create("irq/default_smp_affinity", 0600, NULL,
225 &default_affinity_proc_fops);
226#endif
227}
228
174void init_irq_proc(void) 229void init_irq_proc(void)
175{ 230{
176 int i; 231 int i;
@@ -180,6 +235,8 @@ void init_irq_proc(void)
180 if (!root_irq_dir) 235 if (!root_irq_dir)
181 return; 236 return;
182 237
238 register_default_affinity_proc();
239
183 /* 240 /*
184 * Create entries for all existing IRQs. 241 * Create entries for all existing IRQs.
185 */ 242 */