aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/interrupt.h4
-rw-r--r--include/linux/irq.h1
-rw-r--r--kernel/irq/chip.c14
-rw-r--r--kernel/irq/manage.c49
4 files changed, 61 insertions, 7 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 cb2e77a3f7f7..5e7c6ee8c35c 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -69,6 +69,7 @@ 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 */
72 73
73#ifdef CONFIG_IRQ_PER_CPU 74#ifdef CONFIG_IRQ_PER_CPU
74# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) 75# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 13c68e71b726..b08c0d24f202 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -382,7 +382,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
382 382
383 spin_lock(&desc->lock); 383 spin_lock(&desc->lock);
384 desc->status &= ~IRQ_INPROGRESS; 384 desc->status &= ~IRQ_INPROGRESS;
385 if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) 385
386 if (unlikely(desc->status & IRQ_ONESHOT))
387 desc->status |= IRQ_MASKED;
388 else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
386 desc->chip->unmask(irq); 389 desc->chip->unmask(irq);
387out_unlock: 390out_unlock:
388 spin_unlock(&desc->lock); 391 spin_unlock(&desc->lock);
@@ -478,8 +481,13 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
478 kstat_incr_irqs_this_cpu(irq, desc); 481 kstat_incr_irqs_this_cpu(irq, desc);
479 482
480 /* Start handling the irq */ 483 /* Start handling the irq */
481 if (desc->chip->ack) 484 if (unlikely(desc->status & IRQ_ONESHOT)) {
482 desc->chip->ack(irq); 485 desc->status |= IRQ_MASKED;
486 mask_ack_irq(desc, irq);
487 } else {
488 if (desc->chip->ack)
489 desc->chip->ack(irq);
490 }
483 491
484 /* Mark the IRQ currently in progress.*/ 492 /* Mark the IRQ currently in progress.*/
485 desc->status |= IRQ_INPROGRESS; 493 desc->status |= IRQ_INPROGRESS;
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index d222515a5a06..d7f7b5fd2476 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -436,6 +436,16 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
436 return ret; 436 return ret;
437} 437}
438 438
439/*
440 * Default primary interrupt handler for threaded interrupts. Is
441 * assigned as primary handler when request_threaded_irq is called
442 * with handler == NULL. Useful for oneshot interrupts.
443 */
444static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
445{
446 return IRQ_WAKE_THREAD;
447}
448
439static int irq_wait_for_interrupt(struct irqaction *action) 449static int irq_wait_for_interrupt(struct irqaction *action)
440{ 450{
441 while (!kthread_should_stop()) { 451 while (!kthread_should_stop()) {
@@ -451,6 +461,21 @@ static int irq_wait_for_interrupt(struct irqaction *action)
451 return -1; 461 return -1;
452} 462}
453 463
464/*
465 * Oneshot interrupts keep the irq line masked until the threaded
466 * handler finished. unmask if the interrupt has not been disabled and
467 * is marked MASKED.
468 */
469static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
470{
471 spin_lock_irq(&desc->lock);
472 if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
473 desc->status &= ~IRQ_MASKED;
474 desc->chip->unmask(irq);
475 }
476 spin_unlock_irq(&desc->lock);
477}
478
454#ifdef CONFIG_SMP 479#ifdef CONFIG_SMP
455/* 480/*
456 * Check whether we need to change the affinity of the interrupt thread. 481 * Check whether we need to change the affinity of the interrupt thread.
@@ -492,7 +517,7 @@ static int irq_thread(void *data)
492 struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; 517 struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, };
493 struct irqaction *action = data; 518 struct irqaction *action = data;
494 struct irq_desc *desc = irq_to_desc(action->irq); 519 struct irq_desc *desc = irq_to_desc(action->irq);
495 int wake; 520 int wake, oneshot = desc->status & IRQ_ONESHOT;
496 521
497 sched_setscheduler(current, SCHED_FIFO, &param); 522 sched_setscheduler(current, SCHED_FIFO, &param);
498 current->irqaction = action; 523 current->irqaction = action;
@@ -518,6 +543,9 @@ static int irq_thread(void *data)
518 spin_unlock_irq(&desc->lock); 543 spin_unlock_irq(&desc->lock);
519 544
520 action->thread_fn(action->irq, action->dev_id); 545 action->thread_fn(action->irq, action->dev_id);
546
547 if (oneshot)
548 irq_finalize_oneshot(action->irq, desc);
521 } 549 }
522 550
523 wake = atomic_dec_and_test(&desc->threads_active); 551 wake = atomic_dec_and_test(&desc->threads_active);
@@ -590,6 +618,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
590 rand_initialize_irq(irq); 618 rand_initialize_irq(irq);
591 } 619 }
592 620
621 /* Oneshot interrupts are not allowed with shared */
622 if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
623 return -EINVAL;
624
593 /* 625 /*
594 * Threaded handler ? 626 * Threaded handler ?
595 */ 627 */
@@ -663,9 +695,12 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
663 desc->status |= IRQ_PER_CPU; 695 desc->status |= IRQ_PER_CPU;
664#endif 696#endif
665 697
666 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | 698 desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |
667 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); 699 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
668 700
701 if (new->flags & IRQF_ONESHOT)
702 desc->status |= IRQ_ONESHOT;
703
669 if (!(desc->status & IRQ_NOAUTOEN)) { 704 if (!(desc->status & IRQ_NOAUTOEN)) {
670 desc->depth = 0; 705 desc->depth = 0;
671 desc->status &= ~IRQ_DISABLED; 706 desc->status &= ~IRQ_DISABLED;
@@ -878,6 +913,8 @@ EXPORT_SYMBOL(free_irq);
878 * @irq: Interrupt line to allocate 913 * @irq: Interrupt line to allocate
879 * @handler: Function to be called when the IRQ occurs. 914 * @handler: Function to be called when the IRQ occurs.
880 * Primary handler for threaded interrupts 915 * Primary handler for threaded interrupts
916 * If NULL and thread_fn != NULL the default
917 * primary handler is installed
881 * @thread_fn: Function called from the irq handler thread 918 * @thread_fn: Function called from the irq handler thread
882 * If NULL, no irq thread is created 919 * If NULL, no irq thread is created
883 * @irqflags: Interrupt type flags 920 * @irqflags: Interrupt type flags
@@ -957,8 +994,12 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
957 994
958 if (desc->status & IRQ_NOREQUEST) 995 if (desc->status & IRQ_NOREQUEST)
959 return -EINVAL; 996 return -EINVAL;
960 if (!handler) 997
961 return -EINVAL; 998 if (!handler) {
999 if (!thread_fn)
1000 return -EINVAL;
1001 handler = irq_default_primary_handler;
1002 }
962 1003
963 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); 1004 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
964 if (!action) 1005 if (!action)