diff options
Diffstat (limited to 'kernel/irq')
-rw-r--r-- | kernel/irq/manage.c | 33 | ||||
-rw-r--r-- | kernel/irq/proc.c | 59 |
2 files changed, 83 insertions, 9 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 628b5572a7c2..909b2231fa93 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 | ||
20 | cpumask_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 |
@@ -102,6 +104,27 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask) | |||
102 | return 0; | 104 | return 0; |
103 | } | 105 | } |
104 | 106 | ||
107 | #ifndef CONFIG_AUTO_IRQ_AFFINITY | ||
108 | /* | ||
109 | * Generic version of the affinity autoselector. | ||
110 | */ | ||
111 | int 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 | |||
105 | #endif | 128 | #endif |
106 | 129 | ||
107 | /** | 130 | /** |
@@ -361,7 +384,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
361 | 384 | ||
362 | /* Setup the type (level, edge polarity) if configured: */ | 385 | /* Setup the type (level, edge polarity) if configured: */ |
363 | if (new->flags & IRQF_TRIGGER_MASK) { | 386 | if (new->flags & IRQF_TRIGGER_MASK) { |
364 | if (desc->chip && desc->chip->set_type) | 387 | if (desc->chip->set_type) |
365 | desc->chip->set_type(irq, | 388 | desc->chip->set_type(irq, |
366 | new->flags & IRQF_TRIGGER_MASK); | 389 | new->flags & IRQF_TRIGGER_MASK); |
367 | else | 390 | else |
@@ -371,8 +394,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
371 | */ | 394 | */ |
372 | printk(KERN_WARNING "No IRQF_TRIGGER set_type " | 395 | printk(KERN_WARNING "No IRQF_TRIGGER set_type " |
373 | "function for IRQ %d (%s)\n", irq, | 396 | "function for IRQ %d (%s)\n", irq, |
374 | desc->chip ? desc->chip->name : | 397 | desc->chip->name); |
375 | "unknown"); | ||
376 | } else | 398 | } else |
377 | compat_irq_chip_set_default_handler(desc); | 399 | compat_irq_chip_set_default_handler(desc); |
378 | 400 | ||
@@ -389,6 +411,9 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
389 | } else | 411 | } else |
390 | /* Undo nested disables: */ | 412 | /* Undo nested disables: */ |
391 | desc->depth = 1; | 413 | desc->depth = 1; |
414 | |||
415 | /* Set default affinity mask once everything is setup */ | ||
416 | irq_select_affinity(irq); | ||
392 | } | 417 | } |
393 | /* Reset broken irq detection when installing new handler */ | 418 | /* Reset broken irq detection when installing new handler */ |
394 | desc->irq_count = 0; | 419 | desc->irq_count = 0; |
@@ -578,8 +603,6 @@ int request_irq(unsigned int irq, irq_handler_t handler, | |||
578 | action->next = NULL; | 603 | action->next = NULL; |
579 | action->dev_id = dev_id; | 604 | action->dev_id = dev_id; |
580 | 605 | ||
581 | select_smp_affinity(irq); | ||
582 | |||
583 | #ifdef CONFIG_DEBUG_SHIRQ | 606 | #ifdef CONFIG_DEBUG_SHIRQ |
584 | if (irqflags & IRQF_SHARED) { | 607 | if (irqflags & IRQF_SHARED) { |
585 | /* | 608 | /* |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index c2f2ccb0549a..6c6d35d68ee9 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
@@ -44,7 +44,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, | |||
44 | unsigned long count, void *data) | 44 | unsigned long count, void *data) |
45 | { | 45 | { |
46 | unsigned int irq = (int)(long)data, full_count = count, err; | 46 | unsigned int irq = (int)(long)data, full_count = count, err; |
47 | cpumask_t new_value, tmp; | 47 | cpumask_t new_value; |
48 | 48 | ||
49 | if (!irq_desc[irq].chip->set_affinity || no_irq_affinity || | 49 | if (!irq_desc[irq].chip->set_affinity || no_irq_affinity || |
50 | irq_balancing_disabled(irq)) | 50 | irq_balancing_disabled(irq)) |
@@ -62,17 +62,51 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer, | |||
62 | * way to make the system unusable accidentally :-) At least | 62 | * way to make the system unusable accidentally :-) At least |
63 | * one online CPU still has to be targeted. | 63 | * one online CPU still has to be targeted. |
64 | */ | 64 | */ |
65 | cpus_and(tmp, new_value, cpu_online_map); | 65 | if (!cpus_intersects(new_value, cpu_online_map)) |
66 | if (cpus_empty(tmp)) | ||
67 | /* Special case for empty set - allow the architecture | 66 | /* Special case for empty set - allow the architecture |
68 | code to set default SMP affinity. */ | 67 | code to set default SMP affinity. */ |
69 | return select_smp_affinity(irq) ? -EINVAL : full_count; | 68 | return irq_select_affinity(irq) ? -EINVAL : full_count; |
70 | 69 | ||
71 | irq_set_affinity(irq, new_value); | 70 | irq_set_affinity(irq, new_value); |
72 | 71 | ||
73 | return full_count; | 72 | return full_count; |
74 | } | 73 | } |
75 | 74 | ||
75 | static int default_affinity_read(char *page, char **start, off_t off, | ||
76 | int count, int *eof, void *data) | ||
77 | { | ||
78 | int len = cpumask_scnprintf(page, count, irq_default_affinity); | ||
79 | if (count - len < 2) | ||
80 | return -EINVAL; | ||
81 | len += sprintf(page + len, "\n"); | ||
82 | return len; | ||
83 | } | ||
84 | |||
85 | static int default_affinity_write(struct file *file, const char __user *buffer, | ||
86 | unsigned long count, void *data) | ||
87 | { | ||
88 | unsigned int full_count = count, err; | ||
89 | cpumask_t new_value; | ||
90 | |||
91 | err = cpumask_parse_user(buffer, count, new_value); | ||
92 | if (err) | ||
93 | return err; | ||
94 | |||
95 | if (!is_affinity_mask_valid(new_value)) | ||
96 | return -EINVAL; | ||
97 | |||
98 | /* | ||
99 | * Do not allow disabling IRQs completely - it's a too easy | ||
100 | * way to make the system unusable accidentally :-) At least | ||
101 | * one online CPU still has to be targeted. | ||
102 | */ | ||
103 | if (!cpus_intersects(new_value, cpu_online_map)) | ||
104 | return -EINVAL; | ||
105 | |||
106 | irq_default_affinity = new_value; | ||
107 | |||
108 | return full_count; | ||
109 | } | ||
76 | #endif | 110 | #endif |
77 | 111 | ||
78 | static int irq_spurious_read(char *page, char **start, off_t off, | 112 | static int irq_spurious_read(char *page, char **start, off_t off, |
@@ -171,6 +205,21 @@ void unregister_handler_proc(unsigned int irq, struct irqaction *action) | |||
171 | remove_proc_entry(action->dir->name, irq_desc[irq].dir); | 205 | remove_proc_entry(action->dir->name, irq_desc[irq].dir); |
172 | } | 206 | } |
173 | 207 | ||
208 | void register_default_affinity_proc(void) | ||
209 | { | ||
210 | #ifdef CONFIG_SMP | ||
211 | struct proc_dir_entry *entry; | ||
212 | |||
213 | /* create /proc/irq/default_smp_affinity */ | ||
214 | entry = create_proc_entry("default_smp_affinity", 0600, root_irq_dir); | ||
215 | if (entry) { | ||
216 | entry->data = NULL; | ||
217 | entry->read_proc = default_affinity_read; | ||
218 | entry->write_proc = default_affinity_write; | ||
219 | } | ||
220 | #endif | ||
221 | } | ||
222 | |||
174 | void init_irq_proc(void) | 223 | void init_irq_proc(void) |
175 | { | 224 | { |
176 | int i; | 225 | int i; |
@@ -180,6 +229,8 @@ void init_irq_proc(void) | |||
180 | if (!root_irq_dir) | 229 | if (!root_irq_dir) |
181 | return; | 230 | return; |
182 | 231 | ||
232 | register_default_affinity_proc(); | ||
233 | |||
183 | /* | 234 | /* |
184 | * Create entries for all existing IRQs. | 235 | * Create entries for all existing IRQs. |
185 | */ | 236 | */ |