diff options
| -rw-r--r-- | include/linux/interrupt.h | 4 | ||||
| -rw-r--r-- | include/linux/irq.h | 10 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 74 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 13 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 102 |
5 files changed, 194 insertions, 9 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 35e7df1e9f30..1ac57e522a1f 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
| @@ -50,6 +50,9 @@ | |||
| 50 | * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is | 50 | * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is |
| 51 | * registered first in an shared interrupt is considered for | 51 | * registered first in an shared interrupt is considered for |
| 52 | * performance reasons) | 52 | * performance reasons) |
| 53 | * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. | ||
| 54 | * Used by threaded interrupts which need to keep the | ||
| 55 | * irq line disabled until the threaded handler has been run. | ||
| 53 | */ | 56 | */ |
| 54 | #define IRQF_DISABLED 0x00000020 | 57 | #define IRQF_DISABLED 0x00000020 |
| 55 | #define IRQF_SAMPLE_RANDOM 0x00000040 | 58 | #define IRQF_SAMPLE_RANDOM 0x00000040 |
| @@ -59,6 +62,7 @@ | |||
| 59 | #define IRQF_PERCPU 0x00000400 | 62 | #define IRQF_PERCPU 0x00000400 |
| 60 | #define IRQF_NOBALANCING 0x00000800 | 63 | #define IRQF_NOBALANCING 0x00000800 |
| 61 | #define IRQF_IRQPOLL 0x00001000 | 64 | #define IRQF_IRQPOLL 0x00001000 |
| 65 | #define IRQF_ONESHOT 0x00002000 | ||
| 62 | 66 | ||
| 63 | /* | 67 | /* |
| 64 | * Bits used by threaded handlers: | 68 | * Bits used by threaded handlers: |
diff --git a/include/linux/irq.h b/include/linux/irq.h index 9e9eb76faf81..ae9653dbcd78 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
| @@ -69,6 +69,8 @@ typedef void (*irq_flow_handler_t)(unsigned int irq, | |||
| 69 | #define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */ | 69 | #define IRQ_MOVE_PCNTXT 0x01000000 /* IRQ migration from process context */ |
| 70 | #define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/ | 70 | #define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/ |
| 71 | #define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */ | 71 | #define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */ |
| 72 | #define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */ | ||
| 73 | #define IRQ_NESTED_THREAD 0x10000000 /* IRQ is nested into another, no own handler thread */ | ||
| 72 | 74 | ||
| 73 | #ifdef CONFIG_IRQ_PER_CPU | 75 | #ifdef CONFIG_IRQ_PER_CPU |
| 74 | # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) | 76 | # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) |
| @@ -100,6 +102,9 @@ struct msi_desc; | |||
| 100 | * @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ | 102 | * @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ |
| 101 | * @set_wake: enable/disable power-management wake-on of an IRQ | 103 | * @set_wake: enable/disable power-management wake-on of an IRQ |
| 102 | * | 104 | * |
| 105 | * @bus_lock: function to lock access to slow bus (i2c) chips | ||
| 106 | * @bus_sync_unlock: function to sync and unlock slow bus (i2c) chips | ||
| 107 | * | ||
| 103 | * @release: release function solely used by UML | 108 | * @release: release function solely used by UML |
| 104 | * @typename: obsoleted by name, kept as migration helper | 109 | * @typename: obsoleted by name, kept as migration helper |
| 105 | */ | 110 | */ |
| @@ -123,6 +128,9 @@ struct irq_chip { | |||
| 123 | int (*set_type)(unsigned int irq, unsigned int flow_type); | 128 | int (*set_type)(unsigned int irq, unsigned int flow_type); |
| 124 | int (*set_wake)(unsigned int irq, unsigned int on); | 129 | int (*set_wake)(unsigned int irq, unsigned int on); |
| 125 | 130 | ||
| 131 | void (*bus_lock)(unsigned int irq); | ||
| 132 | void (*bus_sync_unlock)(unsigned int irq); | ||
| 133 | |||
| 126 | /* Currently used only by UML, might disappear one day.*/ | 134 | /* Currently used only by UML, might disappear one day.*/ |
| 127 | #ifdef CONFIG_IRQ_RELEASE_METHOD | 135 | #ifdef CONFIG_IRQ_RELEASE_METHOD |
| 128 | void (*release)(unsigned int irq, void *dev_id); | 136 | void (*release)(unsigned int irq, void *dev_id); |
| @@ -373,6 +381,8 @@ set_irq_chained_handler(unsigned int irq, | |||
| 373 | __set_irq_handler(irq, handle, 1, NULL); | 381 | __set_irq_handler(irq, handle, 1, NULL); |
| 374 | } | 382 | } |
| 375 | 383 | ||
| 384 | extern void set_irq_nested_thread(unsigned int irq, int nest); | ||
| 385 | |||
| 376 | extern void set_irq_noprobe(unsigned int irq); | 386 | extern void set_irq_noprobe(unsigned int irq); |
| 377 | extern void set_irq_probe(unsigned int irq); | 387 | extern void set_irq_probe(unsigned int irq); |
| 378 | 388 | ||
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 13c68e71b726..c1660194d115 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -222,6 +222,34 @@ int set_irq_chip_data(unsigned int irq, void *data) | |||
| 222 | } | 222 | } |
| 223 | EXPORT_SYMBOL(set_irq_chip_data); | 223 | EXPORT_SYMBOL(set_irq_chip_data); |
| 224 | 224 | ||
| 225 | /** | ||
| 226 | * set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq | ||
| 227 | * | ||
| 228 | * @irq: Interrupt number | ||
| 229 | * @nest: 0 to clear / 1 to set the IRQ_NESTED_THREAD flag | ||
| 230 | * | ||
| 231 | * The IRQ_NESTED_THREAD flag indicates that on | ||
| 232 | * request_threaded_irq() no separate interrupt thread should be | ||
| 233 | * created for the irq as the handler are called nested in the | ||
| 234 | * context of a demultiplexing interrupt handler thread. | ||
| 235 | */ | ||
| 236 | void set_irq_nested_thread(unsigned int irq, int nest) | ||
| 237 | { | ||
| 238 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 239 | unsigned long flags; | ||
| 240 | |||
| 241 | if (!desc) | ||
| 242 | return; | ||
| 243 | |||
| 244 | spin_lock_irqsave(&desc->lock, flags); | ||
| 245 | if (nest) | ||
| 246 | desc->status |= IRQ_NESTED_THREAD; | ||
| 247 | else | ||
| 248 | desc->status &= ~IRQ_NESTED_THREAD; | ||
| 249 | spin_unlock_irqrestore(&desc->lock, flags); | ||
| 250 | } | ||
| 251 | EXPORT_SYMBOL_GPL(set_irq_nested_thread); | ||
| 252 | |||
| 225 | /* | 253 | /* |
| 226 | * default enable function | 254 | * default enable function |
| 227 | */ | 255 | */ |
| @@ -299,6 +327,45 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) | |||
| 299 | } | 327 | } |
| 300 | } | 328 | } |
| 301 | 329 | ||
| 330 | /* | ||
| 331 | * handle_nested_irq - Handle a nested irq from a irq thread | ||
| 332 | * @irq: the interrupt number | ||
| 333 | * | ||
| 334 | * Handle interrupts which are nested into a threaded interrupt | ||
| 335 | * handler. The handler function is called inside the calling | ||
| 336 | * threads context. | ||
| 337 | */ | ||
| 338 | void handle_nested_irq(unsigned int irq) | ||
| 339 | { | ||
| 340 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 341 | struct irqaction *action; | ||
| 342 | irqreturn_t action_ret; | ||
| 343 | |||
| 344 | might_sleep(); | ||
| 345 | |||
| 346 | spin_lock_irq(&desc->lock); | ||
| 347 | |||
| 348 | kstat_incr_irqs_this_cpu(irq, desc); | ||
| 349 | |||
| 350 | action = desc->action; | ||
| 351 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) | ||
| 352 | goto out_unlock; | ||
| 353 | |||
| 354 | desc->status |= IRQ_INPROGRESS; | ||
| 355 | spin_unlock_irq(&desc->lock); | ||
| 356 | |||
| 357 | action_ret = action->thread_fn(action->irq, action->dev_id); | ||
| 358 | if (!noirqdebug) | ||
| 359 | note_interrupt(irq, desc, action_ret); | ||
| 360 | |||
| 361 | spin_lock_irq(&desc->lock); | ||
| 362 | desc->status &= ~IRQ_INPROGRESS; | ||
| 363 | |||
| 364 | out_unlock: | ||
| 365 | spin_unlock_irq(&desc->lock); | ||
| 366 | } | ||
| 367 | EXPORT_SYMBOL_GPL(handle_nested_irq); | ||
| 368 | |||
| 302 | /** | 369 | /** |
| 303 | * handle_simple_irq - Simple and software-decoded IRQs. | 370 | * handle_simple_irq - Simple and software-decoded IRQs. |
| 304 | * @irq: the interrupt number | 371 | * @irq: the interrupt number |
| @@ -382,7 +449,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
| 382 | 449 | ||
| 383 | spin_lock(&desc->lock); | 450 | spin_lock(&desc->lock); |
| 384 | desc->status &= ~IRQ_INPROGRESS; | 451 | desc->status &= ~IRQ_INPROGRESS; |
| 385 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | 452 | |
| 453 | if (unlikely(desc->status & IRQ_ONESHOT)) | ||
| 454 | desc->status |= IRQ_MASKED; | ||
| 455 | else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
| 386 | desc->chip->unmask(irq); | 456 | desc->chip->unmask(irq); |
| 387 | out_unlock: | 457 | out_unlock: |
| 388 | spin_unlock(&desc->lock); | 458 | spin_unlock(&desc->lock); |
| @@ -572,6 +642,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 572 | desc->chip = &dummy_irq_chip; | 642 | desc->chip = &dummy_irq_chip; |
| 573 | } | 643 | } |
| 574 | 644 | ||
| 645 | chip_bus_lock(irq, desc); | ||
| 575 | spin_lock_irqsave(&desc->lock, flags); | 646 | spin_lock_irqsave(&desc->lock, flags); |
| 576 | 647 | ||
| 577 | /* Uninstall? */ | 648 | /* Uninstall? */ |
| @@ -591,6 +662,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 591 | desc->chip->startup(irq); | 662 | desc->chip->startup(irq); |
| 592 | } | 663 | } |
| 593 | spin_unlock_irqrestore(&desc->lock, flags); | 664 | spin_unlock_irqrestore(&desc->lock, flags); |
| 665 | chip_bus_sync_unlock(irq, desc); | ||
| 594 | } | 666 | } |
| 595 | EXPORT_SYMBOL_GPL(__set_irq_handler); | 667 | EXPORT_SYMBOL_GPL(__set_irq_handler); |
| 596 | 668 | ||
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index e70ed5592eb9..1b5d742c6a77 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -44,6 +44,19 @@ extern int irq_select_affinity_usr(unsigned int irq); | |||
| 44 | 44 | ||
| 45 | extern void irq_set_thread_affinity(struct irq_desc *desc); | 45 | extern void irq_set_thread_affinity(struct irq_desc *desc); |
| 46 | 46 | ||
| 47 | /* Inline functions for support of irq chips on slow busses */ | ||
| 48 | static inline void chip_bus_lock(unsigned int irq, struct irq_desc *desc) | ||
| 49 | { | ||
| 50 | if (unlikely(desc->chip->bus_lock)) | ||
| 51 | desc->chip->bus_lock(irq); | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline void chip_bus_sync_unlock(unsigned int irq, struct irq_desc *desc) | ||
| 55 | { | ||
| 56 | if (unlikely(desc->chip->bus_sync_unlock)) | ||
| 57 | desc->chip->bus_sync_unlock(irq); | ||
| 58 | } | ||
| 59 | |||
| 47 | /* | 60 | /* |
| 48 | * Debugging printout: | 61 | * Debugging printout: |
| 49 | */ | 62 | */ |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0ec9ed831737..bde4c667d24d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -230,9 +230,11 @@ void disable_irq_nosync(unsigned int irq) | |||
| 230 | if (!desc) | 230 | if (!desc) |
| 231 | return; | 231 | return; |
| 232 | 232 | ||
| 233 | chip_bus_lock(irq, desc); | ||
| 233 | spin_lock_irqsave(&desc->lock, flags); | 234 | spin_lock_irqsave(&desc->lock, flags); |
| 234 | __disable_irq(desc, irq, false); | 235 | __disable_irq(desc, irq, false); |
| 235 | spin_unlock_irqrestore(&desc->lock, flags); | 236 | spin_unlock_irqrestore(&desc->lock, flags); |
| 237 | chip_bus_sync_unlock(irq, desc); | ||
| 236 | } | 238 | } |
| 237 | EXPORT_SYMBOL(disable_irq_nosync); | 239 | EXPORT_SYMBOL(disable_irq_nosync); |
| 238 | 240 | ||
| @@ -294,7 +296,8 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) | |||
| 294 | * matches the last disable, processing of interrupts on this | 296 | * matches the last disable, processing of interrupts on this |
| 295 | * IRQ line is re-enabled. | 297 | * IRQ line is re-enabled. |
| 296 | * | 298 | * |
| 297 | * This function may be called from IRQ context. | 299 | * This function may be called from IRQ context only when |
| 300 | * desc->chip->bus_lock and desc->chip->bus_sync_unlock are NULL ! | ||
| 298 | */ | 301 | */ |
| 299 | void enable_irq(unsigned int irq) | 302 | void enable_irq(unsigned int irq) |
| 300 | { | 303 | { |
| @@ -304,9 +307,11 @@ void enable_irq(unsigned int irq) | |||
| 304 | if (!desc) | 307 | if (!desc) |
| 305 | return; | 308 | return; |
| 306 | 309 | ||
| 310 | chip_bus_lock(irq, desc); | ||
| 307 | spin_lock_irqsave(&desc->lock, flags); | 311 | spin_lock_irqsave(&desc->lock, flags); |
| 308 | __enable_irq(desc, irq, false); | 312 | __enable_irq(desc, irq, false); |
| 309 | spin_unlock_irqrestore(&desc->lock, flags); | 313 | spin_unlock_irqrestore(&desc->lock, flags); |
| 314 | chip_bus_sync_unlock(irq, desc); | ||
| 310 | } | 315 | } |
| 311 | EXPORT_SYMBOL(enable_irq); | 316 | EXPORT_SYMBOL(enable_irq); |
| 312 | 317 | ||
| @@ -436,6 +441,26 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
| 436 | return ret; | 441 | return ret; |
| 437 | } | 442 | } |
| 438 | 443 | ||
| 444 | /* | ||
| 445 | * Default primary interrupt handler for threaded interrupts. Is | ||
| 446 | * assigned as primary handler when request_threaded_irq is called | ||
| 447 | * with handler == NULL. Useful for oneshot interrupts. | ||
| 448 | */ | ||
| 449 | static irqreturn_t irq_default_primary_handler(int irq, void *dev_id) | ||
| 450 | { | ||
| 451 | return IRQ_WAKE_THREAD; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* | ||
| 455 | * Primary handler for nested threaded interrupts. Should never be | ||
| 456 | * called. | ||
| 457 | */ | ||
| 458 | static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id) | ||
| 459 | { | ||
| 460 | WARN(1, "Primary handler called for nested irq %d\n", irq); | ||
| 461 | return IRQ_NONE; | ||
| 462 | } | ||
| 463 | |||
| 439 | static int irq_wait_for_interrupt(struct irqaction *action) | 464 | static int irq_wait_for_interrupt(struct irqaction *action) |
| 440 | { | 465 | { |
| 441 | while (!kthread_should_stop()) { | 466 | while (!kthread_should_stop()) { |
| @@ -451,6 +476,23 @@ static int irq_wait_for_interrupt(struct irqaction *action) | |||
| 451 | return -1; | 476 | return -1; |
| 452 | } | 477 | } |
| 453 | 478 | ||
| 479 | /* | ||
| 480 | * Oneshot interrupts keep the irq line masked until the threaded | ||
| 481 | * handler finished. unmask if the interrupt has not been disabled and | ||
| 482 | * is marked MASKED. | ||
| 483 | */ | ||
| 484 | static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) | ||
| 485 | { | ||
| 486 | chip_bus_lock(irq, desc); | ||
| 487 | spin_lock_irq(&desc->lock); | ||
| 488 | if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) { | ||
| 489 | desc->status &= ~IRQ_MASKED; | ||
| 490 | desc->chip->unmask(irq); | ||
| 491 | } | ||
| 492 | spin_unlock_irq(&desc->lock); | ||
| 493 | chip_bus_sync_unlock(irq, desc); | ||
| 494 | } | ||
| 495 | |||
| 454 | #ifdef CONFIG_SMP | 496 | #ifdef CONFIG_SMP |
| 455 | /* | 497 | /* |
| 456 | * Check whether we need to change the affinity of the interrupt thread. | 498 | * Check whether we need to change the affinity of the interrupt thread. |
| @@ -492,7 +534,7 @@ static int irq_thread(void *data) | |||
| 492 | struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; | 534 | struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; |
| 493 | struct irqaction *action = data; | 535 | struct irqaction *action = data; |
| 494 | struct irq_desc *desc = irq_to_desc(action->irq); | 536 | struct irq_desc *desc = irq_to_desc(action->irq); |
| 495 | int wake; | 537 | int wake, oneshot = desc->status & IRQ_ONESHOT; |
| 496 | 538 | ||
| 497 | sched_setscheduler(current, SCHED_FIFO, ¶m); | 539 | sched_setscheduler(current, SCHED_FIFO, ¶m); |
| 498 | current->irqaction = action; | 540 | current->irqaction = action; |
| @@ -518,6 +560,9 @@ static int irq_thread(void *data) | |||
| 518 | spin_unlock_irq(&desc->lock); | 560 | spin_unlock_irq(&desc->lock); |
| 519 | 561 | ||
| 520 | action->thread_fn(action->irq, action->dev_id); | 562 | action->thread_fn(action->irq, action->dev_id); |
| 563 | |||
| 564 | if (oneshot) | ||
| 565 | irq_finalize_oneshot(action->irq, desc); | ||
| 521 | } | 566 | } |
| 522 | 567 | ||
| 523 | wake = atomic_dec_and_test(&desc->threads_active); | 568 | wake = atomic_dec_and_test(&desc->threads_active); |
| @@ -565,7 +610,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 565 | struct irqaction *old, **old_ptr; | 610 | struct irqaction *old, **old_ptr; |
| 566 | const char *old_name = NULL; | 611 | const char *old_name = NULL; |
| 567 | unsigned long flags; | 612 | unsigned long flags; |
| 568 | int shared = 0; | 613 | int nested, shared = 0; |
| 569 | int ret; | 614 | int ret; |
| 570 | 615 | ||
| 571 | if (!desc) | 616 | if (!desc) |
| @@ -590,10 +635,32 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 590 | rand_initialize_irq(irq); | 635 | rand_initialize_irq(irq); |
| 591 | } | 636 | } |
| 592 | 637 | ||
| 638 | /* Oneshot interrupts are not allowed with shared */ | ||
| 639 | if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED)) | ||
| 640 | return -EINVAL; | ||
| 641 | |||
| 642 | /* | ||
| 643 | * Check whether the interrupt nests into another interrupt | ||
| 644 | * thread. | ||
| 645 | */ | ||
| 646 | nested = desc->status & IRQ_NESTED_THREAD; | ||
| 647 | if (nested) { | ||
| 648 | if (!new->thread_fn) | ||
| 649 | return -EINVAL; | ||
| 650 | /* | ||
| 651 | * Replace the primary handler which was provided from | ||
| 652 | * the driver for non nested interrupt handling by the | ||
| 653 | * dummy function which warns when called. | ||
| 654 | */ | ||
| 655 | new->handler = irq_nested_primary_handler; | ||
| 656 | } | ||
| 657 | |||
| 593 | /* | 658 | /* |
| 594 | * Threaded handler ? | 659 | * Create a handler thread when a thread function is supplied |
| 660 | * and the interrupt does not nest into another interrupt | ||
| 661 | * thread. | ||
| 595 | */ | 662 | */ |
| 596 | if (new->thread_fn) { | 663 | if (new->thread_fn && !nested) { |
| 597 | struct task_struct *t; | 664 | struct task_struct *t; |
| 598 | 665 | ||
| 599 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, | 666 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, |
| @@ -662,9 +729,12 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 662 | desc->status |= IRQ_PER_CPU; | 729 | desc->status |= IRQ_PER_CPU; |
| 663 | #endif | 730 | #endif |
| 664 | 731 | ||
| 665 | desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | | 732 | desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT | |
| 666 | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); | 733 | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); |
| 667 | 734 | ||
| 735 | if (new->flags & IRQF_ONESHOT) | ||
| 736 | desc->status |= IRQ_ONESHOT; | ||
| 737 | |||
| 668 | if (!(desc->status & IRQ_NOAUTOEN)) { | 738 | if (!(desc->status & IRQ_NOAUTOEN)) { |
| 669 | desc->depth = 0; | 739 | desc->depth = 0; |
| 670 | desc->status &= ~IRQ_DISABLED; | 740 | desc->status &= ~IRQ_DISABLED; |
| @@ -875,7 +945,14 @@ EXPORT_SYMBOL_GPL(remove_irq); | |||
| 875 | */ | 945 | */ |
| 876 | void free_irq(unsigned int irq, void *dev_id) | 946 | void free_irq(unsigned int irq, void *dev_id) |
| 877 | { | 947 | { |
| 948 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 949 | |||
| 950 | if (!desc) | ||
| 951 | return; | ||
| 952 | |||
| 953 | chip_bus_lock(irq, desc); | ||
| 878 | kfree(__free_irq(irq, dev_id)); | 954 | kfree(__free_irq(irq, dev_id)); |
| 955 | chip_bus_sync_unlock(irq, desc); | ||
| 879 | } | 956 | } |
| 880 | EXPORT_SYMBOL(free_irq); | 957 | EXPORT_SYMBOL(free_irq); |
| 881 | 958 | ||
| @@ -884,6 +961,8 @@ EXPORT_SYMBOL(free_irq); | |||
| 884 | * @irq: Interrupt line to allocate | 961 | * @irq: Interrupt line to allocate |
| 885 | * @handler: Function to be called when the IRQ occurs. | 962 | * @handler: Function to be called when the IRQ occurs. |
| 886 | * Primary handler for threaded interrupts | 963 | * Primary handler for threaded interrupts |
| 964 | * If NULL and thread_fn != NULL the default | ||
| 965 | * primary handler is installed | ||
| 887 | * @thread_fn: Function called from the irq handler thread | 966 | * @thread_fn: Function called from the irq handler thread |
| 888 | * If NULL, no irq thread is created | 967 | * If NULL, no irq thread is created |
| 889 | * @irqflags: Interrupt type flags | 968 | * @irqflags: Interrupt type flags |
| @@ -963,8 +1042,12 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
| 963 | 1042 | ||
| 964 | if (desc->status & IRQ_NOREQUEST) | 1043 | if (desc->status & IRQ_NOREQUEST) |
| 965 | return -EINVAL; | 1044 | return -EINVAL; |
| 966 | if (!handler) | 1045 | |
| 967 | return -EINVAL; | 1046 | if (!handler) { |
| 1047 | if (!thread_fn) | ||
| 1048 | return -EINVAL; | ||
| 1049 | handler = irq_default_primary_handler; | ||
| 1050 | } | ||
| 968 | 1051 | ||
| 969 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); | 1052 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); |
| 970 | if (!action) | 1053 | if (!action) |
| @@ -976,7 +1059,10 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, | |||
| 976 | action->name = devname; | 1059 | action->name = devname; |
| 977 | action->dev_id = dev_id; | 1060 | action->dev_id = dev_id; |
| 978 | 1061 | ||
| 1062 | chip_bus_lock(irq, desc); | ||
| 979 | retval = __setup_irq(irq, desc, action); | 1063 | retval = __setup_irq(irq, desc, action); |
| 1064 | chip_bus_sync_unlock(irq, desc); | ||
| 1065 | |||
| 980 | if (retval) | 1066 | if (retval) |
| 981 | kfree(action); | 1067 | kfree(action); |
| 982 | 1068 | ||
