Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 158186
b: refs/heads/master
c: 399b5da
h: refs/heads/master
v: v3
  • Loading branch information
Thomas Gleixner committed Aug 17, 2009
1 parent 21c1792 commit 1f05ff0
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 70aedd24d20e75198f5a0b11750faabbb56924e2
refs/heads/master: 399b5da29b9f851eb7b96e2882097127f003e87c
3 changes: 3 additions & 0 deletions trunk/include/linux/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef void (*irq_flow_handler_t)(unsigned int irq,
#define IRQ_AFFINITY_SET 0x02000000 /* IRQ affinity was set from userspace*/
#define IRQ_SUSPENDED 0x04000000 /* IRQ has gone through suspend sequence */
#define IRQ_ONESHOT 0x08000000 /* IRQ is not unmasked after hardirq */
#define IRQ_NESTED_THREAD 0x10000000 /* IRQ is nested into another, no own handler thread */

#ifdef CONFIG_IRQ_PER_CPU
# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
Expand Down Expand Up @@ -386,6 +387,8 @@ set_irq_chained_handler(unsigned int irq,
__set_irq_handler(irq, handle, 1, NULL);
}

extern void set_irq_nested_thread(unsigned int irq, int nest);

extern void set_irq_noprobe(unsigned int irq);
extern void set_irq_probe(unsigned int irq);

Expand Down
67 changes: 67 additions & 0 deletions trunk/kernel/irq/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,34 @@ int set_irq_chip_data(unsigned int irq, void *data)
}
EXPORT_SYMBOL(set_irq_chip_data);

/**
* set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq
*
* @irq: Interrupt number
* @nest: 0 to clear / 1 to set the IRQ_NESTED_THREAD flag
*
* The IRQ_NESTED_THREAD flag indicates that on
* request_threaded_irq() no separate interrupt thread should be
* created for the irq as the handler are called nested in the
* context of a demultiplexing interrupt handler thread.
*/
void set_irq_nested_thread(unsigned int irq, int nest)
{
struct irq_desc *desc = irq_to_desc(irq);
unsigned long flags;

if (!desc)
return;

spin_lock_irqsave(&desc->lock, flags);
if (nest)
desc->status |= IRQ_NESTED_THREAD;
else
desc->status &= ~IRQ_NESTED_THREAD;
spin_unlock_irqrestore(&desc->lock, flags);
}
EXPORT_SYMBOL_GPL(set_irq_nested_thread);

/*
* default enable function
*/
Expand Down Expand Up @@ -299,6 +327,45 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
}
}

/*
* handle_nested_irq - Handle a nested irq from a irq thread
* @irq: the interrupt number
*
* Handle interrupts which are nested into a threaded interrupt
* handler. The handler function is called inside the calling
* threads context.
*/
void handle_nested_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irqaction *action;
irqreturn_t action_ret;

might_sleep();

spin_lock_irq(&desc->lock);

kstat_incr_irqs_this_cpu(irq, desc);

action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock;

desc->status |= IRQ_INPROGRESS;
spin_unlock_irq(&desc->lock);

action_ret = action->thread_fn(action->irq, action->dev_id);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);

spin_lock_irq(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;

out_unlock:
spin_unlock_irq(&desc->lock);
}
EXPORT_SYMBOL_GPL(handle_nested_irq);

/**
* handle_simple_irq - Simple and software-decoded IRQs.
* @irq: the interrupt number
Expand Down
34 changes: 31 additions & 3 deletions trunk/kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,16 @@ static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
return IRQ_WAKE_THREAD;
}

/*
* Primary handler for nested threaded interrupts. Should never be
* called.
*/
static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id)
{
WARN(1, "Primary handler called for nested irq %d\n", irq);
return IRQ_NONE;
}

static int irq_wait_for_interrupt(struct irqaction *action)
{
while (!kthread_should_stop()) {
Expand Down Expand Up @@ -600,7 +610,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
struct irqaction *old, **old_ptr;
const char *old_name = NULL;
unsigned long flags;
int shared = 0;
int nested, shared = 0;
int ret;

if (!desc)
Expand Down Expand Up @@ -630,9 +640,27 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
return -EINVAL;

/*
* Threaded handler ?
* Check whether the interrupt nests into another interrupt
* thread.
*/
nested = desc->status & IRQ_NESTED_THREAD;
if (nested) {
if (!new->thread_fn)
return -EINVAL;
/*
* Replace the primary handler which was provided from
* the driver for non nested interrupt handling by the
* dummy function which warns when called.
*/
new->handler = irq_nested_primary_handler;
}

/*
* Create a handler thread when a thread function is supplied
* and the interrupt does not nest into another interrupt
* thread.
*/
if (new->thread_fn) {
if (new->thread_fn && !nested) {
struct task_struct *t;

t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
Expand Down

0 comments on commit 1f05ff0

Please sign in to comment.