aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-08-13 06:17:22 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-08-17 04:54:05 -0400
commitb25c340c195447afb1860da580fe2a85a6b652c5 (patch)
tree99578092c1e6100f50786e44a1a4fe9cfdb11662 /kernel/irq
parentb2add73dbf93fd50f00564d7abc3e2b9aa9dd20c (diff)
genirq: Add oneshot support
For threaded interrupt handlers we expect the hard interrupt handler part to mask the interrupt on the originating device. The interrupt line itself is reenabled after the hard interrupt handler has executed. This requires access to the originating device from hard interrupt context which is not always possible. There are devices which can only be accessed via a bus (i2c, spi, ...). The bus access requires thread context. For such devices we need to keep the interrupt line masked until the threaded handler has executed. Add a new flag IRQF_ONESHOT which allows drivers to request that the interrupt is not unmasked after the hard interrupt context handler has been executed and the thread has been woken. The interrupt line is unmasked after the thread handler function has been executed. Note that for now IRQF_ONESHOT cannot be used with IRQF_SHARED to avoid complex accounting mechanisms. For oneshot interrupts the primary handler simply returns IRQ_WAKE_THREAD and does nothing else. A generic implementation irq_default_primary_handler() is provided to avoid useless copies all over the place. It is automatically installed when request_threaded_irq() is called with handler=NULL and thread_fn!=NULL. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Trilok Soni <soni.trilok@gmail.com> Cc: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Joonyoung Shim <jy0922.shim@samsung.com> Cc: m.szyprowski@samsung.com Cc: t.fujak@samsung.com Cc: kyungmin.park@samsung.com, Cc: David Brownell <david-b@pacbell.net> Cc: Daniel Ribeiro <drwyrm@gmail.com> Cc: arve@android.com Cc: Barry Song <21cnbao@gmail.com>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/chip.c14
-rw-r--r--kernel/irq/manage.c49
2 files changed, 56 insertions, 7 deletions
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)