aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-07-26 09:30:40 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-26 09:30:40 -0400
commit1503af661947b7a4a09355cc2ae6aa0d43f16776 (patch)
tree5bfcfadf2dd2d98c2ad251c96d7ee43a6903819a /kernel/irq/manage.c
parenta31863168660c6b6f6c7ffe05bb6a38e97803326 (diff)
parent024e8ac04453b3525448c31ef39848cf675ba6db (diff)
Merge branch 'linus' into x86/header-guards
Conflicts: include/asm-x86/gpio.h include/asm-x86/ide.h Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r--kernel/irq/manage.c107
1 files changed, 70 insertions, 37 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 77a51be36010..f8914b92b664 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -217,6 +217,17 @@ void enable_irq(unsigned int irq)
217} 217}
218EXPORT_SYMBOL(enable_irq); 218EXPORT_SYMBOL(enable_irq);
219 219
220int set_irq_wake_real(unsigned int irq, unsigned int on)
221{
222 struct irq_desc *desc = irq_desc + irq;
223 int ret = -ENXIO;
224
225 if (desc->chip->set_wake)
226 ret = desc->chip->set_wake(irq, on);
227
228 return ret;
229}
230
220/** 231/**
221 * set_irq_wake - control irq power management wakeup 232 * set_irq_wake - control irq power management wakeup
222 * @irq: interrupt to control 233 * @irq: interrupt to control
@@ -233,30 +244,32 @@ int set_irq_wake(unsigned int irq, unsigned int on)
233{ 244{
234 struct irq_desc *desc = irq_desc + irq; 245 struct irq_desc *desc = irq_desc + irq;
235 unsigned long flags; 246 unsigned long flags;
236 int ret = -ENXIO; 247 int ret = 0;
237 int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake;
238 248
239 /* wakeup-capable irqs can be shared between drivers that 249 /* wakeup-capable irqs can be shared between drivers that
240 * don't need to have the same sleep mode behaviors. 250 * don't need to have the same sleep mode behaviors.
241 */ 251 */
242 spin_lock_irqsave(&desc->lock, flags); 252 spin_lock_irqsave(&desc->lock, flags);
243 if (on) { 253 if (on) {
244 if (desc->wake_depth++ == 0) 254 if (desc->wake_depth++ == 0) {
245 desc->status |= IRQ_WAKEUP; 255 ret = set_irq_wake_real(irq, on);
246 else 256 if (ret)
247 set_wake = NULL; 257 desc->wake_depth = 0;
258 else
259 desc->status |= IRQ_WAKEUP;
260 }
248 } else { 261 } else {
249 if (desc->wake_depth == 0) { 262 if (desc->wake_depth == 0) {
250 printk(KERN_WARNING "Unbalanced IRQ %d " 263 WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
251 "wake disable\n", irq); 264 } else if (--desc->wake_depth == 0) {
252 WARN_ON(1); 265 ret = set_irq_wake_real(irq, on);
253 } else if (--desc->wake_depth == 0) 266 if (ret)
254 desc->status &= ~IRQ_WAKEUP; 267 desc->wake_depth = 1;
255 else 268 else
256 set_wake = NULL; 269 desc->status &= ~IRQ_WAKEUP;
270 }
257 } 271 }
258 if (set_wake) 272
259 ret = desc->chip->set_wake(irq, on);
260 spin_unlock_irqrestore(&desc->lock, flags); 273 spin_unlock_irqrestore(&desc->lock, flags);
261 return ret; 274 return ret;
262} 275}
@@ -293,6 +306,30 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
293 desc->handle_irq = NULL; 306 desc->handle_irq = NULL;
294} 307}
295 308
309static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
310 unsigned long flags)
311{
312 int ret;
313
314 if (!chip || !chip->set_type) {
315 /*
316 * IRQF_TRIGGER_* but the PIC does not support multiple
317 * flow-types?
318 */
319 pr_warning("No set_type function for IRQ %d (%s)\n", irq,
320 chip ? (chip->name ? : "unknown") : "unknown");
321 return 0;
322 }
323
324 ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK);
325
326 if (ret)
327 pr_err("setting flow type for irq %u failed (%pF)\n",
328 irq, chip->set_type);
329
330 return ret;
331}
332
296/* 333/*
297 * Internal function to register an irqaction - typically used to 334 * Internal function to register an irqaction - typically used to
298 * allocate special interrupts that are part of the architecture. 335 * allocate special interrupts that are part of the architecture.
@@ -304,6 +341,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
304 const char *old_name = NULL; 341 const char *old_name = NULL;
305 unsigned long flags; 342 unsigned long flags;
306 int shared = 0; 343 int shared = 0;
344 int ret;
307 345
308 if (irq >= NR_IRQS) 346 if (irq >= NR_IRQS)
309 return -EINVAL; 347 return -EINVAL;
@@ -361,35 +399,23 @@ int setup_irq(unsigned int irq, struct irqaction *new)
361 shared = 1; 399 shared = 1;
362 } 400 }
363 401
364 *p = new;
365
366 /* Exclude IRQ from balancing */
367 if (new->flags & IRQF_NOBALANCING)
368 desc->status |= IRQ_NO_BALANCING;
369
370 if (!shared) { 402 if (!shared) {
371 irq_chip_set_defaults(desc->chip); 403 irq_chip_set_defaults(desc->chip);
372 404
373#if defined(CONFIG_IRQ_PER_CPU)
374 if (new->flags & IRQF_PERCPU)
375 desc->status |= IRQ_PER_CPU;
376#endif
377
378 /* Setup the type (level, edge polarity) if configured: */ 405 /* Setup the type (level, edge polarity) if configured: */
379 if (new->flags & IRQF_TRIGGER_MASK) { 406 if (new->flags & IRQF_TRIGGER_MASK) {
380 if (desc->chip->set_type) 407 ret = __irq_set_trigger(desc->chip, irq, new->flags);
381 desc->chip->set_type(irq, 408
382 new->flags & IRQF_TRIGGER_MASK); 409 if (ret) {
383 else 410 spin_unlock_irqrestore(&desc->lock, flags);
384 /* 411 return ret;
385 * IRQF_TRIGGER_* but the PIC does not support 412 }
386 * multiple flow-types?
387 */
388 printk(KERN_WARNING "No IRQF_TRIGGER set_type "
389 "function for IRQ %d (%s)\n", irq,
390 desc->chip->name);
391 } else 413 } else
392 compat_irq_chip_set_default_handler(desc); 414 compat_irq_chip_set_default_handler(desc);
415#if defined(CONFIG_IRQ_PER_CPU)
416 if (new->flags & IRQF_PERCPU)
417 desc->status |= IRQ_PER_CPU;
418#endif
393 419
394 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | 420 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
395 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); 421 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
@@ -408,6 +434,13 @@ int setup_irq(unsigned int irq, struct irqaction *new)
408 /* Set default affinity mask once everything is setup */ 434 /* Set default affinity mask once everything is setup */
409 irq_select_affinity(irq); 435 irq_select_affinity(irq);
410 } 436 }
437
438 *p = new;
439
440 /* Exclude IRQ from balancing */
441 if (new->flags & IRQF_NOBALANCING)
442 desc->status |= IRQ_NO_BALANCING;
443
411 /* Reset broken irq detection when installing new handler */ 444 /* Reset broken irq detection when installing new handler */
412 desc->irq_count = 0; 445 desc->irq_count = 0;
413 desc->irqs_unhandled = 0; 446 desc->irqs_unhandled = 0;