2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* linux/kernel/irq/manage.c
|
|
|
|
*
|
2006-06-29 11:24:50 +02:00
|
|
|
* Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
|
|
|
|
* Copyright (C) 2005-2006 Thomas Gleixner
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
|
|
|
* This file contains driver APIs to the irq subsystem.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/irq.h>
|
2009-03-23 18:28:15 +01:00
|
|
|
#include <linux/kthread.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/random.h>
|
|
|
|
#include <linux/interrupt.h>
|
2008-04-29 09:59:25 +02:00
|
|
|
#include <linux/slab.h>
|
2009-03-23 18:28:15 +01:00
|
|
|
#include <linux/sched.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
#include "internals.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* synchronize_irq - wait for pending IRQ handlers (on other CPUs)
|
2005-11-07 10:01:06 +01:00
|
|
|
* @irq: interrupt number to wait for
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
|
|
|
* This function waits for any pending IRQ handlers for this interrupt
|
|
|
|
* to complete before returning. If you use this function while
|
|
|
|
* holding a resource the IRQ handler may need you will deadlock.
|
|
|
|
*
|
|
|
|
* This function may be called - with care - from IRQ context.
|
|
|
|
*/
|
|
|
|
void synchronize_irq(unsigned int irq)
|
|
|
|
{
|
2008-08-20 05:50:17 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2007-10-23 05:26:25 +02:00
|
|
|
unsigned int status;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
2005-11-03 15:51:18 +01:00
|
|
|
return;
|
|
|
|
|
2007-10-23 05:26:25 +02:00
|
|
|
do {
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait until we're out of the critical section. This might
|
|
|
|
* give the wrong answer due to the lack of memory barriers.
|
|
|
|
*/
|
|
|
|
while (desc->status & IRQ_INPROGRESS)
|
|
|
|
cpu_relax();
|
|
|
|
|
|
|
|
/* Ok, that indicated we're done: double-check carefully. */
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2007-10-23 05:26:25 +02:00
|
|
|
status = desc->status;
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2007-10-23 05:26:25 +02:00
|
|
|
|
|
|
|
/* Oops, that failed? */
|
|
|
|
} while (status & IRQ_INPROGRESS);
|
2009-03-23 18:28:15 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We made sure that no hardirq handler is running. Now verify
|
|
|
|
* that no threaded handlers are active.
|
|
|
|
*/
|
|
|
|
wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(synchronize_irq);
|
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
cpumask_var_t irq_default_affinity;
|
|
|
|
|
2007-02-16 10:27:25 +01:00
|
|
|
/**
|
|
|
|
* irq_can_set_affinity - Check if the affinity of a given irq can be set
|
|
|
|
* @irq: Interrupt to check
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int irq_can_set_affinity(unsigned int irq)
|
|
|
|
{
|
2008-08-20 05:50:05 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2007-02-16 10:27:25 +01:00
|
|
|
|
|
|
|
if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip ||
|
|
|
|
!desc->chip->set_affinity)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-07-21 11:09:39 +02:00
|
|
|
/**
|
|
|
|
* irq_set_thread_affinity - Notify irq threads to adjust affinity
|
|
|
|
* @desc: irq descriptor which has affitnity changed
|
|
|
|
*
|
|
|
|
* We just set IRQTF_AFFINITY and delegate the affinity setting
|
|
|
|
* to the interrupt thread itself. We can not call
|
|
|
|
* set_cpus_allowed_ptr() here as we hold desc->lock and this
|
|
|
|
* code can be called from hard interrupt context.
|
|
|
|
*/
|
|
|
|
void irq_set_thread_affinity(struct irq_desc *desc)
|
2009-03-23 18:28:15 +01:00
|
|
|
{
|
|
|
|
struct irqaction *action = desc->action;
|
|
|
|
|
|
|
|
while (action) {
|
|
|
|
if (action->thread)
|
2009-07-21 11:09:39 +02:00
|
|
|
set_bit(IRQTF_AFFINITY, &action->thread_flags);
|
2009-03-23 18:28:15 +01:00
|
|
|
action = action->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-16 10:27:25 +01:00
|
|
|
/**
|
|
|
|
* irq_set_affinity - Set the irq affinity of a given irq
|
|
|
|
* @irq: Interrupt to set affinity
|
|
|
|
* @cpumask: cpumask
|
|
|
|
*
|
|
|
|
*/
|
2008-12-13 11:50:26 +01:00
|
|
|
int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
|
2007-02-16 10:27:25 +01:00
|
|
|
{
|
2008-08-20 05:50:05 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2008-11-07 13:18:30 +01:00
|
|
|
unsigned long flags;
|
2007-02-16 10:27:25 +01:00
|
|
|
|
|
|
|
if (!desc->chip->set_affinity)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2008-11-07 13:18:30 +01:00
|
|
|
|
2007-02-16 10:27:25 +01:00
|
|
|
#ifdef CONFIG_GENERIC_PENDING_IRQ
|
2009-04-28 02:59:53 +02:00
|
|
|
if (desc->status & IRQ_MOVE_PCNTXT) {
|
|
|
|
if (!desc->chip->set_affinity(irq, cpumask)) {
|
|
|
|
cpumask_copy(desc->affinity, cpumask);
|
2009-07-21 11:09:39 +02:00
|
|
|
irq_set_thread_affinity(desc);
|
2009-04-28 02:59:53 +02:00
|
|
|
}
|
|
|
|
}
|
2009-04-14 00:20:58 +02:00
|
|
|
else {
|
2008-11-07 13:18:30 +01:00
|
|
|
desc->status |= IRQ_MOVE_PENDING;
|
2009-01-11 06:58:08 +01:00
|
|
|
cpumask_copy(desc->pending_mask, cpumask);
|
2008-11-07 13:18:30 +01:00
|
|
|
}
|
2007-02-16 10:27:25 +01:00
|
|
|
#else
|
2009-04-28 02:59:53 +02:00
|
|
|
if (!desc->chip->set_affinity(irq, cpumask)) {
|
|
|
|
cpumask_copy(desc->affinity, cpumask);
|
2009-07-21 11:09:39 +02:00
|
|
|
irq_set_thread_affinity(desc);
|
2009-04-28 02:59:53 +02:00
|
|
|
}
|
2007-02-16 10:27:25 +01:00
|
|
|
#endif
|
2008-11-07 13:18:30 +01:00
|
|
|
desc->status |= IRQ_AFFINITY_SET;
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2007-02-16 10:27:25 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-29 20:02:52 +02:00
|
|
|
#ifndef CONFIG_AUTO_IRQ_AFFINITY
|
|
|
|
/*
|
|
|
|
* Generic version of the affinity autoselector.
|
|
|
|
*/
|
2009-02-08 20:24:47 +01:00
|
|
|
static int setup_affinity(unsigned int irq, struct irq_desc *desc)
|
2008-05-29 20:02:52 +02:00
|
|
|
{
|
|
|
|
if (!irq_can_set_affinity(irq))
|
|
|
|
return 0;
|
|
|
|
|
2008-11-07 13:18:30 +01:00
|
|
|
/*
|
|
|
|
* Preserve an userspace affinity setup, but make sure that
|
|
|
|
* one of the targets is online.
|
|
|
|
*/
|
2008-11-07 13:58:46 +01:00
|
|
|
if (desc->status & (IRQ_AFFINITY_SET | IRQ_NO_BALANCING)) {
|
2009-01-11 06:58:08 +01:00
|
|
|
if (cpumask_any_and(desc->affinity, cpu_online_mask)
|
2008-12-13 11:50:26 +01:00
|
|
|
< nr_cpu_ids)
|
|
|
|
goto set_affinity;
|
2008-11-07 13:18:30 +01:00
|
|
|
else
|
|
|
|
desc->status &= ~IRQ_AFFINITY_SET;
|
|
|
|
}
|
|
|
|
|
2009-01-11 06:58:08 +01:00
|
|
|
cpumask_and(desc->affinity, cpu_online_mask, irq_default_affinity);
|
2008-12-13 11:50:26 +01:00
|
|
|
set_affinity:
|
2009-01-11 06:58:08 +01:00
|
|
|
desc->chip->set_affinity(irq, desc->affinity);
|
2008-05-29 20:02:52 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-11-07 13:18:30 +01:00
|
|
|
#else
|
2009-02-08 20:24:47 +01:00
|
|
|
static inline int setup_affinity(unsigned int irq, struct irq_desc *d)
|
2008-11-07 13:18:30 +01:00
|
|
|
{
|
|
|
|
return irq_select_affinity(irq);
|
|
|
|
}
|
2008-05-29 20:02:52 +02:00
|
|
|
#endif
|
|
|
|
|
2008-11-07 13:18:30 +01:00
|
|
|
/*
|
|
|
|
* Called when affinity is set via /proc/irq
|
|
|
|
*/
|
|
|
|
int irq_select_affinity_usr(unsigned int irq)
|
|
|
|
{
|
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
|
unsigned long flags;
|
|
|
|
int ret;
|
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2009-02-08 20:24:47 +01:00
|
|
|
ret = setup_affinity(irq, desc);
|
2009-03-23 18:28:15 +01:00
|
|
|
if (!ret)
|
2009-07-21 11:09:39 +02:00
|
|
|
irq_set_thread_affinity(desc);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2008-11-07 13:18:30 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2009-02-08 20:24:47 +01:00
|
|
|
static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
|
2008-11-07 13:18:30 +01:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-17 00:20:36 +02:00
|
|
|
#endif
|
|
|
|
|
2009-03-16 22:33:49 +01:00
|
|
|
void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
|
|
|
|
{
|
|
|
|
if (suspend) {
|
|
|
|
if (!desc->action || (desc->action->flags & IRQF_TIMER))
|
|
|
|
return;
|
|
|
|
desc->status |= IRQ_SUSPENDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!desc->depth++) {
|
|
|
|
desc->status |= IRQ_DISABLED;
|
|
|
|
desc->chip->disable(irq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/**
|
|
|
|
* disable_irq_nosync - disable an irq without waiting
|
|
|
|
* @irq: Interrupt to disable
|
|
|
|
*
|
|
|
|
* Disable the selected interrupt line. Disables and Enables are
|
|
|
|
* nested.
|
|
|
|
* Unlike disable_irq(), this function does not ensure existing
|
|
|
|
* instances of the IRQ handler have completed before returning.
|
|
|
|
*
|
|
|
|
* This function may be called from IRQ context.
|
|
|
|
*/
|
|
|
|
void disable_irq_nosync(unsigned int irq)
|
|
|
|
{
|
2008-10-16 09:55:00 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2005-04-17 00:20:36 +02:00
|
|
|
unsigned long flags;
|
|
|
|
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
2005-11-03 15:51:18 +01:00
|
|
|
return;
|
|
|
|
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_lock(irq, desc);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2009-03-16 22:33:49 +01:00
|
|
|
__disable_irq(desc, irq, false);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_sync_unlock(irq, desc);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(disable_irq_nosync);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* disable_irq - disable an irq and wait for completion
|
|
|
|
* @irq: Interrupt to disable
|
|
|
|
*
|
|
|
|
* Disable the selected interrupt line. Enables and Disables are
|
|
|
|
* nested.
|
|
|
|
* This function waits for any pending IRQ handlers for this interrupt
|
|
|
|
* to complete before returning. If you use this function while
|
|
|
|
* holding a resource the IRQ handler may need you will deadlock.
|
|
|
|
*
|
|
|
|
* This function may be called - with care - from IRQ context.
|
|
|
|
*/
|
|
|
|
void disable_irq(unsigned int irq)
|
|
|
|
{
|
2008-10-16 09:55:00 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
2005-11-03 15:51:18 +01:00
|
|
|
return;
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
disable_irq_nosync(irq);
|
|
|
|
if (desc->action)
|
|
|
|
synchronize_irq(irq);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(disable_irq);
|
|
|
|
|
2009-03-16 22:33:49 +01:00
|
|
|
void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
|
2008-04-28 17:01:56 +02:00
|
|
|
{
|
2009-03-16 22:33:49 +01:00
|
|
|
if (resume)
|
|
|
|
desc->status &= ~IRQ_SUSPENDED;
|
|
|
|
|
2008-04-28 17:01:56 +02:00
|
|
|
switch (desc->depth) {
|
|
|
|
case 0:
|
2009-03-16 22:33:49 +01:00
|
|
|
err_out:
|
2008-07-26 04:45:36 +02:00
|
|
|
WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
|
2008-04-28 17:01:56 +02:00
|
|
|
break;
|
|
|
|
case 1: {
|
|
|
|
unsigned int status = desc->status & ~IRQ_DISABLED;
|
|
|
|
|
2009-03-16 22:33:49 +01:00
|
|
|
if (desc->status & IRQ_SUSPENDED)
|
|
|
|
goto err_out;
|
2008-04-28 17:01:56 +02:00
|
|
|
/* Prevent probing on this irq: */
|
|
|
|
desc->status = status | IRQ_NOPROBE;
|
|
|
|
check_irq_resend(desc, irq);
|
|
|
|
/* fall-through */
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
desc->depth--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/**
|
|
|
|
* enable_irq - enable handling of an irq
|
|
|
|
* @irq: Interrupt to enable
|
|
|
|
*
|
|
|
|
* Undoes the effect of one call to disable_irq(). If this
|
|
|
|
* matches the last disable, processing of interrupts on this
|
|
|
|
* IRQ line is re-enabled.
|
|
|
|
*
|
2009-08-13 12:17:48 +02:00
|
|
|
* This function may be called from IRQ context only when
|
|
|
|
* desc->chip->bus_lock and desc->chip->bus_sync_unlock are NULL !
|
2005-04-17 00:20:36 +02:00
|
|
|
*/
|
|
|
|
void enable_irq(unsigned int irq)
|
|
|
|
{
|
2008-10-16 09:55:00 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2005-04-17 00:20:36 +02:00
|
|
|
unsigned long flags;
|
|
|
|
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
2005-11-03 15:51:18 +01:00
|
|
|
return;
|
|
|
|
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_lock(irq, desc);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2009-03-16 22:33:49 +01:00
|
|
|
__enable_irq(desc, irq, false);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_sync_unlock(irq, desc);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(enable_irq);
|
|
|
|
|
2008-10-01 23:46:18 +02:00
|
|
|
static int set_irq_wake_real(unsigned int irq, unsigned int on)
|
2008-07-23 14:42:25 +02:00
|
|
|
{
|
2008-08-20 05:50:05 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2008-07-23 14:42:25 +02:00
|
|
|
int ret = -ENXIO;
|
|
|
|
|
|
|
|
if (desc->chip->set_wake)
|
|
|
|
ret = desc->chip->set_wake(irq, on);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-06-29 11:24:55 +02:00
|
|
|
/**
|
|
|
|
* set_irq_wake - control irq power management wakeup
|
|
|
|
* @irq: interrupt to control
|
|
|
|
* @on: enable/disable power management wakeup
|
|
|
|
*
|
2006-07-30 12:03:08 +02:00
|
|
|
* Enable/disable power management wakeup mode, which is
|
|
|
|
* disabled by default. Enables and disables must match,
|
|
|
|
* just as they match for non-wakeup mode support.
|
|
|
|
*
|
|
|
|
* Wakeup mode lets this IRQ wake the system from sleep
|
|
|
|
* states like "suspend to RAM".
|
2006-06-29 11:24:55 +02:00
|
|
|
*/
|
|
|
|
int set_irq_wake(unsigned int irq, unsigned int on)
|
|
|
|
{
|
2008-08-20 05:50:05 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2006-06-29 11:24:55 +02:00
|
|
|
unsigned long flags;
|
2008-07-23 14:42:25 +02:00
|
|
|
int ret = 0;
|
2006-06-29 11:24:55 +02:00
|
|
|
|
2006-07-30 12:03:08 +02:00
|
|
|
/* wakeup-capable irqs can be shared between drivers that
|
|
|
|
* don't need to have the same sleep mode behaviors.
|
|
|
|
*/
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2006-07-30 12:03:08 +02:00
|
|
|
if (on) {
|
2008-07-23 14:42:25 +02:00
|
|
|
if (desc->wake_depth++ == 0) {
|
|
|
|
ret = set_irq_wake_real(irq, on);
|
|
|
|
if (ret)
|
|
|
|
desc->wake_depth = 0;
|
|
|
|
else
|
|
|
|
desc->status |= IRQ_WAKEUP;
|
|
|
|
}
|
2006-07-30 12:03:08 +02:00
|
|
|
} else {
|
|
|
|
if (desc->wake_depth == 0) {
|
2008-07-25 10:45:54 +02:00
|
|
|
WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
|
2008-07-23 14:42:25 +02:00
|
|
|
} else if (--desc->wake_depth == 0) {
|
|
|
|
ret = set_irq_wake_real(irq, on);
|
|
|
|
if (ret)
|
|
|
|
desc->wake_depth = 1;
|
|
|
|
else
|
|
|
|
desc->status &= ~IRQ_WAKEUP;
|
|
|
|
}
|
2006-07-30 12:03:08 +02:00
|
|
|
}
|
2008-07-23 14:42:25 +02:00
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2006-06-29 11:24:55 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(set_irq_wake);
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* Internal function that tells the architecture code whether a
|
|
|
|
* particular irq has been exclusively allocated or is available
|
|
|
|
* for driver use.
|
|
|
|
*/
|
|
|
|
int can_request_irq(unsigned int irq, unsigned long irqflags)
|
|
|
|
{
|
2008-10-16 09:55:00 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2005-04-17 00:20:36 +02:00
|
|
|
struct irqaction *action;
|
2010-03-23 22:40:53 +01:00
|
|
|
unsigned long flags;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (desc->status & IRQ_NOREQUEST)
|
2005-04-17 00:20:36 +02:00
|
|
|
return 0;
|
|
|
|
|
2010-03-23 22:40:53 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2008-08-20 05:50:05 +02:00
|
|
|
action = desc->action;
|
2005-04-17 00:20:36 +02:00
|
|
|
if (action)
|
2006-07-02 04:29:31 +02:00
|
|
|
if (irqflags & action->flags & IRQF_SHARED)
|
2005-04-17 00:20:36 +02:00
|
|
|
action = NULL;
|
|
|
|
|
2010-03-23 22:40:53 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
return !action;
|
|
|
|
}
|
|
|
|
|
2006-06-29 11:24:51 +02:00
|
|
|
void compat_irq_chip_set_default_handler(struct irq_desc *desc)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If the architecture still has not overriden
|
|
|
|
* the flow handler then zap the default. This
|
|
|
|
* should catch incorrect flow-type setting.
|
|
|
|
*/
|
|
|
|
if (desc->handle_irq == &handle_bad_irq)
|
|
|
|
desc->handle_irq = NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-01 23:46:18 +02:00
|
|
|
int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
|
2008-07-24 06:28:54 +02:00
|
|
|
unsigned long flags)
|
|
|
|
{
|
|
|
|
int ret;
|
2008-10-01 23:46:18 +02:00
|
|
|
struct irq_chip *chip = desc->chip;
|
2008-07-24 06:28:54 +02:00
|
|
|
|
|
|
|
if (!chip || !chip->set_type) {
|
|
|
|
/*
|
|
|
|
* IRQF_TRIGGER_* but the PIC does not support multiple
|
|
|
|
* flow-types?
|
|
|
|
*/
|
2008-11-13 11:37:41 +01:00
|
|
|
pr_debug("No set_type function for IRQ %d (%s)\n", irq,
|
2008-07-24 06:28:54 +02:00
|
|
|
chip ? (chip->name ? : "unknown") : "unknown");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-12-01 23:31:38 +01:00
|
|
|
/* caller masked out all except trigger mode flags */
|
|
|
|
ret = chip->set_type(irq, flags);
|
2008-07-24 06:28:54 +02:00
|
|
|
|
|
|
|
if (ret)
|
2008-08-05 22:01:14 +02:00
|
|
|
pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
|
2008-12-01 23:31:38 +01:00
|
|
|
(int)flags, irq, chip->set_type);
|
2008-10-01 23:46:18 +02:00
|
|
|
else {
|
2008-12-01 23:31:38 +01:00
|
|
|
if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
|
|
|
|
flags |= IRQ_LEVEL;
|
2008-10-01 23:46:18 +02:00
|
|
|
/* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
|
2008-12-01 23:31:38 +01:00
|
|
|
desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
|
|
|
|
desc->status |= flags;
|
2008-10-01 23:46:18 +02:00
|
|
|
}
|
2008-07-24 06:28:54 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-08-13 12:17:22 +02:00
|
|
|
/*
|
|
|
|
* Default primary interrupt handler for threaded interrupts. Is
|
|
|
|
* assigned as primary handler when request_threaded_irq is called
|
|
|
|
* with handler == NULL. Useful for oneshot interrupts.
|
|
|
|
*/
|
|
|
|
static irqreturn_t irq_default_primary_handler(int irq, void *dev_id)
|
|
|
|
{
|
|
|
|
return IRQ_WAKE_THREAD;
|
|
|
|
}
|
|
|
|
|
2009-08-13 13:21:38 +02:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
static int irq_wait_for_interrupt(struct irqaction *action)
|
|
|
|
{
|
|
|
|
while (!kthread_should_stop()) {
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2009-03-24 11:46:22 +01:00
|
|
|
|
|
|
|
if (test_and_clear_bit(IRQTF_RUNTHREAD,
|
|
|
|
&action->thread_flags)) {
|
2009-03-23 18:28:15 +01:00
|
|
|
__set_current_state(TASK_RUNNING);
|
|
|
|
return 0;
|
2009-03-24 11:46:22 +01:00
|
|
|
}
|
|
|
|
schedule();
|
2009-03-23 18:28:15 +01:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-08-13 12:17:22 +02:00
|
|
|
/*
|
|
|
|
* Oneshot interrupts keep the irq line masked until the threaded
|
|
|
|
* handler finished. unmask if the interrupt has not been disabled and
|
|
|
|
* is marked MASKED.
|
|
|
|
*/
|
|
|
|
static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
|
|
|
|
{
|
2010-03-09 19:45:54 +01:00
|
|
|
again:
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_lock(irq, desc);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irq(&desc->lock);
|
2010-03-09 19:45:54 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Implausible though it may be we need to protect us against
|
|
|
|
* the following scenario:
|
|
|
|
*
|
|
|
|
* The thread is faster done than the hard interrupt handler
|
|
|
|
* on the other CPU. If we unmask the irq line then the
|
|
|
|
* interrupt can come in again and masks the line, leaves due
|
|
|
|
* to IRQ_INPROGRESS and the irq line is masked forever.
|
|
|
|
*/
|
|
|
|
if (unlikely(desc->status & IRQ_INPROGRESS)) {
|
|
|
|
raw_spin_unlock_irq(&desc->lock);
|
|
|
|
chip_bus_sync_unlock(irq, desc);
|
|
|
|
cpu_relax();
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2009-08-13 12:17:22 +02:00
|
|
|
if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
|
|
|
|
desc->status &= ~IRQ_MASKED;
|
|
|
|
desc->chip->unmask(irq);
|
|
|
|
}
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irq(&desc->lock);
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_sync_unlock(irq, desc);
|
2009-08-13 12:17:22 +02:00
|
|
|
}
|
|
|
|
|
2009-07-22 22:22:32 +02:00
|
|
|
#ifdef CONFIG_SMP
|
2009-07-21 11:09:39 +02:00
|
|
|
/*
|
|
|
|
* Check whether we need to change the affinity of the interrupt thread.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
|
|
|
|
{
|
|
|
|
cpumask_var_t mask;
|
|
|
|
|
|
|
|
if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In case we are out of memory we set IRQTF_AFFINITY again and
|
|
|
|
* try again next time
|
|
|
|
*/
|
|
|
|
if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
|
|
|
|
set_bit(IRQTF_AFFINITY, &action->thread_flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irq(&desc->lock);
|
2009-07-21 11:09:39 +02:00
|
|
|
cpumask_copy(mask, desc->affinity);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irq(&desc->lock);
|
2009-07-21 11:09:39 +02:00
|
|
|
|
|
|
|
set_cpus_allowed_ptr(current, mask);
|
|
|
|
free_cpumask_var(mask);
|
|
|
|
}
|
2009-07-22 22:22:32 +02:00
|
|
|
#else
|
|
|
|
static inline void
|
|
|
|
irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { }
|
|
|
|
#endif
|
2009-07-21 11:09:39 +02:00
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
/*
|
|
|
|
* Interrupt handler thread
|
|
|
|
*/
|
|
|
|
static int irq_thread(void *data)
|
|
|
|
{
|
|
|
|
struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, };
|
|
|
|
struct irqaction *action = data;
|
|
|
|
struct irq_desc *desc = irq_to_desc(action->irq);
|
2009-08-13 12:17:22 +02:00
|
|
|
int wake, oneshot = desc->status & IRQ_ONESHOT;
|
2009-03-23 18:28:15 +01:00
|
|
|
|
|
|
|
sched_setscheduler(current, SCHED_FIFO, ¶m);
|
|
|
|
current->irqaction = action;
|
|
|
|
|
|
|
|
while (!irq_wait_for_interrupt(action)) {
|
|
|
|
|
2009-07-21 11:09:39 +02:00
|
|
|
irq_thread_check_affinity(desc, action);
|
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
atomic_inc(&desc->threads_active);
|
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irq(&desc->lock);
|
2009-03-23 18:28:15 +01:00
|
|
|
if (unlikely(desc->status & IRQ_DISABLED)) {
|
|
|
|
/*
|
|
|
|
* CHECKME: We might need a dedicated
|
|
|
|
* IRQ_THREAD_PENDING flag here, which
|
|
|
|
* retriggers the thread in check_irq_resend()
|
|
|
|
* but AFAICT IRQ_PENDING should be fine as it
|
|
|
|
* retriggers the interrupt itself --- tglx
|
|
|
|
*/
|
|
|
|
desc->status |= IRQ_PENDING;
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irq(&desc->lock);
|
2009-03-23 18:28:15 +01:00
|
|
|
} else {
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irq(&desc->lock);
|
2009-03-23 18:28:15 +01:00
|
|
|
|
|
|
|
action->thread_fn(action->irq, action->dev_id);
|
2009-08-13 12:17:22 +02:00
|
|
|
|
|
|
|
if (oneshot)
|
|
|
|
irq_finalize_oneshot(action->irq, desc);
|
2009-03-23 18:28:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
wake = atomic_dec_and_test(&desc->threads_active);
|
|
|
|
|
|
|
|
if (wake && waitqueue_active(&desc->wait_for_threads))
|
|
|
|
wake_up(&desc->wait_for_threads);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear irqaction. Otherwise exit_irq_thread() would make
|
|
|
|
* fuzz about an active irq thread going into nirvana.
|
|
|
|
*/
|
|
|
|
current->irqaction = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called from do_exit()
|
|
|
|
*/
|
|
|
|
void exit_irq_thread(void)
|
|
|
|
{
|
|
|
|
struct task_struct *tsk = current;
|
|
|
|
|
|
|
|
if (!tsk->irqaction)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printk(KERN_ERR
|
|
|
|
"exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
|
|
|
|
tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the THREAD DIED flag to prevent further wakeups of the
|
|
|
|
* soon to be gone threaded handler.
|
|
|
|
*/
|
|
|
|
set_bit(IRQTF_DIED, &tsk->irqaction->flags);
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* Internal function to register an irqaction - typically used to
|
|
|
|
* allocate special interrupts that are part of the architecture.
|
|
|
|
*/
|
2008-10-16 09:55:00 +02:00
|
|
|
static int
|
2009-02-15 11:21:37 +01:00
|
|
|
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2009-02-17 20:43:37 +01:00
|
|
|
struct irqaction *old, **old_ptr;
|
2006-11-14 11:03:23 +01:00
|
|
|
const char *old_name = NULL;
|
2005-04-17 00:20:36 +02:00
|
|
|
unsigned long flags;
|
2009-08-13 13:21:38 +02:00
|
|
|
int nested, shared = 0;
|
2008-07-24 06:28:54 +02:00
|
|
|
int ret;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
2005-11-03 15:51:18 +01:00
|
|
|
return -EINVAL;
|
|
|
|
|
2006-06-29 11:24:57 +02:00
|
|
|
if (desc->chip == &no_irq_chip)
|
2005-04-17 00:20:36 +02:00
|
|
|
return -ENOSYS;
|
|
|
|
/*
|
|
|
|
* Some drivers like serial.c use request_irq() heavily,
|
|
|
|
* so we have to be careful not to interfere with a
|
|
|
|
* running system.
|
|
|
|
*/
|
2006-07-02 04:29:31 +02:00
|
|
|
if (new->flags & IRQF_SAMPLE_RANDOM) {
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* This function might sleep, we want to call it first,
|
|
|
|
* outside of the atomic block.
|
|
|
|
* Yes, this might clear the entropy pool if the wrong
|
|
|
|
* driver is attempted to be loaded, without actually
|
|
|
|
* installing a new handler, but is this really a problem,
|
|
|
|
* only the sysadmin is able to do this.
|
|
|
|
*/
|
|
|
|
rand_initialize_irq(irq);
|
|
|
|
}
|
|
|
|
|
2009-08-13 12:17:22 +02:00
|
|
|
/* Oneshot interrupts are not allowed with shared */
|
|
|
|
if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
/*
|
2009-08-13 13:21:38 +02:00
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
/*
|
2009-08-13 13:21:38 +02:00
|
|
|
* Create a handler thread when a thread function is supplied
|
|
|
|
* and the interrupt does not nest into another interrupt
|
|
|
|
* thread.
|
2009-03-23 18:28:15 +01:00
|
|
|
*/
|
2009-08-13 13:21:38 +02:00
|
|
|
if (new->thread_fn && !nested) {
|
2009-03-23 18:28:15 +01:00
|
|
|
struct task_struct *t;
|
|
|
|
|
|
|
|
t = kthread_create(irq_thread, new, "irq/%d-%s", irq,
|
|
|
|
new->name);
|
|
|
|
if (IS_ERR(t))
|
|
|
|
return PTR_ERR(t);
|
|
|
|
/*
|
|
|
|
* We keep the reference to the task struct even if
|
|
|
|
* the thread dies to avoid that the interrupt code
|
|
|
|
* references an already freed task_struct.
|
|
|
|
*/
|
|
|
|
get_task_struct(t);
|
|
|
|
new->thread = t;
|
|
|
|
}
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* The following block of code has to be executed atomically
|
|
|
|
*/
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2009-02-17 20:43:37 +01:00
|
|
|
old_ptr = &desc->action;
|
|
|
|
old = *old_ptr;
|
2006-06-29 11:24:40 +02:00
|
|
|
if (old) {
|
2006-06-29 11:24:56 +02:00
|
|
|
/*
|
|
|
|
* Can't share interrupts unless both agree to and are
|
|
|
|
* the same type (level, edge, polarity). So both flag
|
2006-07-02 04:29:31 +02:00
|
|
|
* fields must have IRQF_SHARED set and the bits which
|
2006-06-29 11:24:56 +02:00
|
|
|
* set the trigger type must match.
|
|
|
|
*/
|
2006-07-02 04:29:31 +02:00
|
|
|
if (!((old->flags & new->flags) & IRQF_SHARED) ||
|
2006-11-14 11:03:23 +01:00
|
|
|
((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
|
|
|
|
old_name = old->name;
|
2006-03-25 12:08:23 +01:00
|
|
|
goto mismatch;
|
2006-11-14 11:03:23 +01:00
|
|
|
}
|
2006-03-25 12:08:23 +01:00
|
|
|
|
2006-07-03 02:20:32 +02:00
|
|
|
#if defined(CONFIG_IRQ_PER_CPU)
|
2006-03-25 12:08:23 +01:00
|
|
|
/* All handlers must agree on per-cpuness */
|
2006-07-02 04:29:31 +02:00
|
|
|
if ((old->flags & IRQF_PERCPU) !=
|
|
|
|
(new->flags & IRQF_PERCPU))
|
2006-03-25 12:08:23 +01:00
|
|
|
goto mismatch;
|
|
|
|
#endif
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
/* add new interrupt at end of irq queue */
|
|
|
|
do {
|
2009-02-17 20:43:37 +01:00
|
|
|
old_ptr = &old->next;
|
|
|
|
old = *old_ptr;
|
2005-04-17 00:20:36 +02:00
|
|
|
} while (old);
|
|
|
|
shared = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shared) {
|
2006-06-29 11:24:51 +02:00
|
|
|
irq_chip_set_defaults(desc->chip);
|
2006-06-29 11:24:56 +02:00
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
init_waitqueue_head(&desc->wait_for_threads);
|
|
|
|
|
2006-06-29 11:24:56 +02:00
|
|
|
/* Setup the type (level, edge polarity) if configured: */
|
2006-07-02 04:29:31 +02:00
|
|
|
if (new->flags & IRQF_TRIGGER_MASK) {
|
2008-12-01 23:31:38 +01:00
|
|
|
ret = __irq_set_trigger(desc, irq,
|
|
|
|
new->flags & IRQF_TRIGGER_MASK);
|
2008-07-24 06:28:54 +02:00
|
|
|
|
2009-03-23 18:28:15 +01:00
|
|
|
if (ret)
|
|
|
|
goto out_thread;
|
2006-06-29 11:24:56 +02:00
|
|
|
} else
|
|
|
|
compat_irq_chip_set_default_handler(desc);
|
2008-07-24 06:28:54 +02:00
|
|
|
#if defined(CONFIG_IRQ_PER_CPU)
|
|
|
|
if (new->flags & IRQF_PERCPU)
|
|
|
|
desc->status |= IRQ_PER_CPU;
|
|
|
|
#endif
|
2006-06-29 11:24:51 +02:00
|
|
|
|
2009-08-13 12:17:22 +02:00
|
|
|
desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |
|
2008-04-28 17:01:56 +02:00
|
|
|
IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
|
2006-06-29 11:24:50 +02:00
|
|
|
|
2009-08-13 12:17:22 +02:00
|
|
|
if (new->flags & IRQF_ONESHOT)
|
|
|
|
desc->status |= IRQ_ONESHOT;
|
|
|
|
|
2006-06-29 11:24:50 +02:00
|
|
|
if (!(desc->status & IRQ_NOAUTOEN)) {
|
|
|
|
desc->depth = 0;
|
|
|
|
desc->status &= ~IRQ_DISABLED;
|
2008-09-01 11:12:11 +02:00
|
|
|
desc->chip->startup(irq);
|
2006-06-29 11:24:56 +02:00
|
|
|
} else
|
|
|
|
/* Undo nested disables: */
|
|
|
|
desc->depth = 1;
|
2008-05-29 20:02:52 +02:00
|
|
|
|
2008-11-07 13:58:46 +01:00
|
|
|
/* Exclude IRQ from balancing if requested */
|
|
|
|
if (new->flags & IRQF_NOBALANCING)
|
|
|
|
desc->status |= IRQ_NO_BALANCING;
|
|
|
|
|
2008-05-29 20:02:52 +02:00
|
|
|
/* Set default affinity mask once everything is setup */
|
2009-02-08 20:24:47 +01:00
|
|
|
setup_affinity(irq, desc);
|
2008-10-01 23:46:18 +02:00
|
|
|
|
|
|
|
} else if ((new->flags & IRQF_TRIGGER_MASK)
|
|
|
|
&& (new->flags & IRQF_TRIGGER_MASK)
|
|
|
|
!= (desc->status & IRQ_TYPE_SENSE_MASK)) {
|
|
|
|
/* hope the handler works with the actual trigger mode... */
|
|
|
|
pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
|
|
|
|
irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),
|
|
|
|
(int)(new->flags & IRQF_TRIGGER_MASK));
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2008-07-24 06:28:54 +02:00
|
|
|
|
2009-08-17 14:07:16 +02:00
|
|
|
new->irq = irq;
|
2009-02-17 20:43:37 +01:00
|
|
|
*old_ptr = new;
|
2008-07-24 06:28:54 +02:00
|
|
|
|
2007-01-23 23:16:31 +01:00
|
|
|
/* Reset broken irq detection when installing new handler */
|
|
|
|
desc->irq_count = 0;
|
|
|
|
desc->irqs_unhandled = 0;
|
2008-04-28 17:01:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check whether we disabled the irq via the spurious handler
|
|
|
|
* before. Reenable it and give it another chance.
|
|
|
|
*/
|
|
|
|
if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
|
|
|
|
desc->status &= ~IRQ_SPURIOUS_DISABLED;
|
2009-03-16 22:33:49 +01:00
|
|
|
__enable_irq(desc, irq, false);
|
2008-04-28 17:01:56 +02:00
|
|
|
}
|
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-08-17 14:07:16 +02:00
|
|
|
/*
|
|
|
|
* Strictly no need to wake it up, but hung_task complains
|
|
|
|
* when no hard interrupt wakes the thread up.
|
|
|
|
*/
|
|
|
|
if (new->thread)
|
|
|
|
wake_up_process(new->thread);
|
|
|
|
|
2008-08-20 05:50:11 +02:00
|
|
|
register_irq_proc(irq, desc);
|
2005-04-17 00:20:36 +02:00
|
|
|
new->dir = NULL;
|
|
|
|
register_handler_proc(irq, new);
|
|
|
|
|
|
|
|
return 0;
|
2006-03-25 12:08:23 +01:00
|
|
|
|
|
|
|
mismatch:
|
2007-02-12 09:52:04 +01:00
|
|
|
#ifdef CONFIG_DEBUG_SHIRQ
|
2006-07-02 04:29:31 +02:00
|
|
|
if (!(new->flags & IRQF_PROBE_SHARED)) {
|
2006-07-01 13:35:45 +02:00
|
|
|
printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
|
2006-11-14 11:03:23 +01:00
|
|
|
if (old_name)
|
|
|
|
printk(KERN_ERR "current handler: %s\n", old_name);
|
2006-04-28 03:39:18 +02:00
|
|
|
dump_stack();
|
|
|
|
}
|
2007-02-12 09:52:04 +01:00
|
|
|
#endif
|
2009-03-23 18:28:15 +01:00
|
|
|
ret = -EBUSY;
|
|
|
|
|
|
|
|
out_thread:
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2009-03-23 18:28:15 +01:00
|
|
|
if (new->thread) {
|
|
|
|
struct task_struct *t = new->thread;
|
|
|
|
|
|
|
|
new->thread = NULL;
|
|
|
|
if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))
|
|
|
|
kthread_stop(t);
|
|
|
|
put_task_struct(t);
|
|
|
|
}
|
|
|
|
return ret;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2008-10-16 09:55:00 +02:00
|
|
|
/**
|
|
|
|
* setup_irq - setup an interrupt
|
|
|
|
* @irq: Interrupt line to setup
|
|
|
|
* @act: irqaction for the interrupt
|
|
|
|
*
|
|
|
|
* Used to statically setup interrupts in the early boot process.
|
|
|
|
*/
|
|
|
|
int setup_irq(unsigned int irq, struct irqaction *act)
|
|
|
|
{
|
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
|
|
|
|
|
return __setup_irq(irq, desc, act);
|
|
|
|
}
|
2009-03-12 13:05:59 +01:00
|
|
|
EXPORT_SYMBOL_GPL(setup_irq);
|
2008-10-16 09:55:00 +02:00
|
|
|
|
2009-03-12 13:05:51 +01:00
|
|
|
/*
|
|
|
|
* Internal function to unregister an irqaction - used to free
|
|
|
|
* regular and special interrupts that are part of the architecture.
|
2005-04-17 00:20:36 +02:00
|
|
|
*/
|
2009-03-12 13:05:51 +01:00
|
|
|
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2008-10-16 09:55:00 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
2009-02-17 20:43:37 +01:00
|
|
|
struct irqaction *action, **action_ptr;
|
2005-04-17 00:20:36 +02:00
|
|
|
unsigned long flags;
|
|
|
|
|
2009-02-15 11:29:50 +01:00
|
|
|
WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
|
2008-08-20 05:50:14 +02:00
|
|
|
|
|
|
|
if (!desc)
|
2009-03-12 13:05:42 +01:00
|
|
|
return NULL;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_lock_irqsave(&desc->lock, flags);
|
2009-02-15 11:29:50 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There can be multiple actions per IRQ descriptor, find the right
|
|
|
|
* one based on the dev_id:
|
|
|
|
*/
|
2009-02-17 20:43:37 +01:00
|
|
|
action_ptr = &desc->action;
|
2005-04-17 00:20:36 +02:00
|
|
|
for (;;) {
|
2009-02-17 20:43:37 +01:00
|
|
|
action = *action_ptr;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-02-15 11:29:50 +01:00
|
|
|
if (!action) {
|
|
|
|
WARN(1, "Trying to free already-free IRQ %d\n", irq);
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-03-12 13:05:42 +01:00
|
|
|
return NULL;
|
2009-02-15 11:29:50 +01:00
|
|
|
}
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-02-17 20:28:29 +01:00
|
|
|
if (action->dev_id == dev_id)
|
|
|
|
break;
|
2009-02-17 20:43:37 +01:00
|
|
|
action_ptr = &action->next;
|
2009-02-15 11:29:50 +01:00
|
|
|
}
|
[PATCH] uml: add and use generic hw_controller_type->release
With Chris Wedgwood <cw@f00f.org>
Currently UML must explicitly call the UML-specific
free_irq_by_irq_and_dev() for each free_irq call it's done.
This is needed because ->shutdown and/or ->disable are only called when the
last "action" for that irq is removed.
Instead, for UML shared IRQs (UML IRQs are very often, if not always,
shared), for each dev_id some setup is done, which must be cleared on the
release of that fd. For instance, for each open console a new instance
(i.e. new dev_id) of the same IRQ is requested().
Exactly, a fd is stored in an array (pollfds), which is after read by a
host thread and passed to poll(). Each event registered by poll() triggers
an interrupt. So, for each free_irq() we must remove the corresponding
host fd from the table, which we do via this -release() method.
In this patch we add an appropriate hook for this, and remove all uses of
it by pointing the hook to the said procedure; this is safe to do since the
said procedure.
Also some cosmetic improvements are included.
This is heavily based on some work by Chris Wedgwood, which however didn't
get the patch merged for something I'd call a "misunderstanding" (the need
for this patch wasn't cleanly explained, thus adding the generic hook was
felt as undesirable).
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
CC: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-22 02:16:19 +02:00
|
|
|
|
2009-02-15 11:29:50 +01:00
|
|
|
/* Found it - now remove it from the list of entries: */
|
2009-02-17 20:43:37 +01:00
|
|
|
*action_ptr = action->next;
|
2009-02-15 11:29:50 +01:00
|
|
|
|
|
|
|
/* Currently used only by UML, might disappear one day: */
|
2005-06-22 02:16:24 +02:00
|
|
|
#ifdef CONFIG_IRQ_RELEASE_METHOD
|
2009-02-15 11:29:50 +01:00
|
|
|
if (desc->chip->release)
|
|
|
|
desc->chip->release(irq, dev_id);
|
2005-06-22 02:16:24 +02:00
|
|
|
#endif
|
[PATCH] uml: add and use generic hw_controller_type->release
With Chris Wedgwood <cw@f00f.org>
Currently UML must explicitly call the UML-specific
free_irq_by_irq_and_dev() for each free_irq call it's done.
This is needed because ->shutdown and/or ->disable are only called when the
last "action" for that irq is removed.
Instead, for UML shared IRQs (UML IRQs are very often, if not always,
shared), for each dev_id some setup is done, which must be cleared on the
release of that fd. For instance, for each open console a new instance
(i.e. new dev_id) of the same IRQ is requested().
Exactly, a fd is stored in an array (pollfds), which is after read by a
host thread and passed to poll(). Each event registered by poll() triggers
an interrupt. So, for each free_irq() we must remove the corresponding
host fd from the table, which we do via this -release() method.
In this patch we add an appropriate hook for this, and remove all uses of
it by pointing the hook to the said procedure; this is safe to do since the
said procedure.
Also some cosmetic improvements are included.
This is heavily based on some work by Chris Wedgwood, which however didn't
get the patch merged for something I'd call a "misunderstanding" (the need
for this patch wasn't cleanly explained, thus adding the generic hook was
felt as undesirable).
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
CC: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-22 02:16:19 +02:00
|
|
|
|
2009-02-15 11:29:50 +01:00
|
|
|
/* If this was the last handler, shut down the IRQ line: */
|
|
|
|
if (!desc->action) {
|
|
|
|
desc->status |= IRQ_DISABLED;
|
|
|
|
if (desc->chip->shutdown)
|
|
|
|
desc->chip->shutdown(irq);
|
|
|
|
else
|
|
|
|
desc->chip->disable(irq);
|
|
|
|
}
|
2009-03-23 18:28:15 +01:00
|
|
|
|
2009-11-17 16:46:45 +01:00
|
|
|
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
2009-02-15 11:29:50 +01:00
|
|
|
|
|
|
|
unregister_handler_proc(irq, action);
|
|
|
|
|
|
|
|
/* Make sure it's not being used on another CPU: */
|
|
|
|
synchronize_irq(irq);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-01-30 13:33:24 +01:00
|
|
|
#ifdef CONFIG_DEBUG_SHIRQ
|
2009-02-15 11:29:50 +01:00
|
|
|
/*
|
|
|
|
* It's a shared IRQ -- the driver ought to be prepared for an IRQ
|
|
|
|
* event to happen even now it's being freed, so let's make sure that
|
|
|
|
* is so by doing an extra call to the handler ....
|
|
|
|
*
|
|
|
|
* ( We do this after actually deregistering it, to make sure that a
|
|
|
|
* 'real' IRQ doesn't run in * parallel with our fake. )
|
|
|
|
*/
|
|
|
|
if (action->flags & IRQF_SHARED) {
|
|
|
|
local_irq_save(flags);
|
|
|
|
action->handler(irq, dev_id);
|
|
|
|
local_irq_restore(flags);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2009-02-15 11:29:50 +01:00
|
|
|
#endif
|
2009-08-13 22:05:10 +02:00
|
|
|
|
|
|
|
if (action->thread) {
|
|
|
|
if (!test_bit(IRQTF_DIED, &action->thread_flags))
|
|
|
|
kthread_stop(action->thread);
|
|
|
|
put_task_struct(action->thread);
|
|
|
|
}
|
|
|
|
|
2009-03-12 13:05:42 +01:00
|
|
|
return action;
|
|
|
|
}
|
|
|
|
|
2009-03-12 13:05:51 +01:00
|
|
|
/**
|
|
|
|
* remove_irq - free an interrupt
|
|
|
|
* @irq: Interrupt line to free
|
|
|
|
* @act: irqaction for the interrupt
|
|
|
|
*
|
|
|
|
* Used to remove interrupts statically setup by the early boot process.
|
|
|
|
*/
|
|
|
|
void remove_irq(unsigned int irq, struct irqaction *act)
|
|
|
|
{
|
|
|
|
__free_irq(irq, act->dev_id);
|
|
|
|
}
|
2009-03-12 13:05:59 +01:00
|
|
|
EXPORT_SYMBOL_GPL(remove_irq);
|
2009-03-12 13:05:51 +01:00
|
|
|
|
2009-03-12 13:05:42 +01:00
|
|
|
/**
|
|
|
|
* free_irq - free an interrupt allocated with request_irq
|
|
|
|
* @irq: Interrupt line to free
|
|
|
|
* @dev_id: Device identity to free
|
|
|
|
*
|
|
|
|
* Remove an interrupt handler. The handler is removed and if the
|
|
|
|
* interrupt line is no longer in use by any driver it is disabled.
|
|
|
|
* On a shared IRQ the caller must ensure the interrupt is disabled
|
|
|
|
* on the card it drives before calling this function. The function
|
|
|
|
* does not return until any executing interrupts for this IRQ
|
|
|
|
* have completed.
|
|
|
|
*
|
|
|
|
* This function must not be called from interrupt context.
|
|
|
|
*/
|
|
|
|
void free_irq(unsigned int irq, void *dev_id)
|
|
|
|
{
|
2009-08-13 12:17:48 +02:00
|
|
|
struct irq_desc *desc = irq_to_desc(irq);
|
|
|
|
|
|
|
|
if (!desc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
chip_bus_lock(irq, desc);
|
2009-03-12 13:05:51 +01:00
|
|
|
kfree(__free_irq(irq, dev_id));
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_sync_unlock(irq, desc);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(free_irq);
|
|
|
|
|
|
|
|
/**
|
2009-03-23 18:28:15 +01:00
|
|
|
* request_threaded_irq - allocate an interrupt line
|
2005-04-17 00:20:36 +02:00
|
|
|
* @irq: Interrupt line to allocate
|
2009-03-23 18:28:15 +01:00
|
|
|
* @handler: Function to be called when the IRQ occurs.
|
|
|
|
* Primary handler for threaded interrupts
|
2009-08-13 12:17:22 +02:00
|
|
|
* If NULL and thread_fn != NULL the default
|
|
|
|
* primary handler is installed
|
2009-03-24 11:46:22 +01:00
|
|
|
* @thread_fn: Function called from the irq handler thread
|
|
|
|
* If NULL, no irq thread is created
|
2005-04-17 00:20:36 +02:00
|
|
|
* @irqflags: Interrupt type flags
|
|
|
|
* @devname: An ascii name for the claiming device
|
|
|
|
* @dev_id: A cookie passed back to the handler function
|
|
|
|
*
|
|
|
|
* This call allocates interrupt resources and enables the
|
|
|
|
* interrupt line and IRQ handling. From the point this
|
|
|
|
* call is made your handler function may be invoked. Since
|
|
|
|
* your handler function must clear any interrupt the board
|
|
|
|
* raises, you must take care both to initialise your hardware
|
|
|
|
* and to set up the interrupt handler in the right order.
|
|
|
|
*
|
2009-03-23 18:28:15 +01:00
|
|
|
* If you want to set up a threaded irq handler for your device
|
|
|
|
* then you need to supply @handler and @thread_fn. @handler ist
|
|
|
|
* still called in hard interrupt context and has to check
|
|
|
|
* whether the interrupt originates from the device. If yes it
|
|
|
|
* needs to disable the interrupt on the device and return
|
2009-05-12 20:35:54 +02:00
|
|
|
* IRQ_WAKE_THREAD which will wake up the handler thread and run
|
2009-03-23 18:28:15 +01:00
|
|
|
* @thread_fn. This split handler design is necessary to support
|
|
|
|
* shared interrupts.
|
|
|
|
*
|
2005-04-17 00:20:36 +02:00
|
|
|
* Dev_id must be globally unique. Normally the address of the
|
|
|
|
* device data structure is used as the cookie. Since the handler
|
|
|
|
* receives this value it makes sense to use it.
|
|
|
|
*
|
|
|
|
* If your interrupt is shared you must pass a non NULL dev_id
|
|
|
|
* as this is required when freeing the interrupt.
|
|
|
|
*
|
|
|
|
* Flags:
|
|
|
|
*
|
2006-07-02 04:29:31 +02:00
|
|
|
* IRQF_SHARED Interrupt is shared
|
|
|
|
* IRQF_DISABLED Disable local interrupts while processing
|
|
|
|
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
|
2008-10-01 23:46:18 +02:00
|
|
|
* IRQF_TRIGGER_* Specify active edge(s) or level
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
|
|
|
*/
|
2009-03-23 18:28:15 +01:00
|
|
|
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
|
|
|
|
irq_handler_t thread_fn, unsigned long irqflags,
|
|
|
|
const char *devname, void *dev_id)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2006-06-29 11:24:40 +02:00
|
|
|
struct irqaction *action;
|
2008-08-20 05:50:05 +02:00
|
|
|
struct irq_desc *desc;
|
2008-10-16 09:55:00 +02:00
|
|
|
int retval;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-12-01 23:31:37 +01:00
|
|
|
/*
|
|
|
|
* handle_IRQ_event() always ignores IRQF_DISABLED except for
|
|
|
|
* the _first_ irqaction (sigh). That can cause oopsing, but
|
|
|
|
* the behavior is classified as "will not fix" so we need to
|
|
|
|
* start nudging drivers away from using that idiom.
|
|
|
|
*/
|
2009-02-15 11:21:37 +01:00
|
|
|
if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
|
|
|
|
(IRQF_SHARED|IRQF_DISABLED)) {
|
|
|
|
pr_warning(
|
|
|
|
"IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
|
|
|
|
irq, devname);
|
|
|
|
}
|
2008-12-01 23:31:37 +01:00
|
|
|
|
[PATCH] lockdep: core
Do 'make oldconfig' and accept all the defaults for new config options -
reboot into the kernel and if everything goes well it should boot up fine and
you should have /proc/lockdep and /proc/lockdep_stats files.
Typically if the lock validator finds some problem it will print out
voluminous debug output that begins with "BUG: ..." and which syslog output
can be used by kernel developers to figure out the precise locking scenario.
What does the lock validator do? It "observes" and maps all locking rules as
they occur dynamically (as triggered by the kernel's natural use of spinlocks,
rwlocks, mutexes and rwsems). Whenever the lock validator subsystem detects a
new locking scenario, it validates this new rule against the existing set of
rules. If this new rule is consistent with the existing set of rules then the
new rule is added transparently and the kernel continues as normal. If the
new rule could create a deadlock scenario then this condition is printed out.
When determining validity of locking, all possible "deadlock scenarios" are
considered: assuming arbitrary number of CPUs, arbitrary irq context and task
context constellations, running arbitrary combinations of all the existing
locking scenarios. In a typical system this means millions of separate
scenarios. This is why we call it a "locking correctness" validator - for all
rules that are observed the lock validator proves it with mathematical
certainty that a deadlock could not occur (assuming that the lock validator
implementation itself is correct and its internal data structures are not
corrupted by some other kernel subsystem). [see more details and conditionals
of this statement in include/linux/lockdep.h and
Documentation/lockdep-design.txt]
Furthermore, this "all possible scenarios" property of the validator also
enables the finding of complex, highly unlikely multi-CPU multi-context races
via single single-context rules, increasing the likelyhood of finding bugs
drastically. In practical terms: the lock validator already found a bug in
the upstream kernel that could only occur on systems with 3 or more CPUs, and
which needed 3 very unlikely code sequences to occur at once on the 3 CPUs.
That bug was found and reported on a single-CPU system (!). So in essence a
race will be found "piecemail-wise", triggering all the necessary components
for the race, without having to reproduce the race scenario itself! In its
short existence the lock validator found and reported many bugs before they
actually caused a real deadlock.
To further increase the efficiency of the validator, the mapping is not per
"lock instance", but per "lock-class". For example, all struct inode objects
in the kernel have inode->inotify_mutex. If there are 10,000 inodes cached,
then there are 10,000 lock objects. But ->inotify_mutex is a single "lock
type", and all locking activities that occur against ->inotify_mutex are
"unified" into this single lock-class. The advantage of the lock-class
approach is that all historical ->inotify_mutex uses are mapped into a single
(and as narrow as possible) set of locking rules - regardless of how many
different tasks or inode structures it took to build this set of rules. The
set of rules persist during the lifetime of the kernel.
To see the rough magnitude of checking that the lock validator does, here's a
portion of /proc/lockdep_stats, fresh after bootup:
lock-classes: 694 [max: 2048]
direct dependencies: 1598 [max: 8192]
indirect dependencies: 17896
all direct dependencies: 16206
dependency chains: 1910 [max: 8192]
in-hardirq chains: 17
in-softirq chains: 105
in-process chains: 1065
stack-trace entries: 38761 [max: 131072]
combined max dependencies: 2033928
hardirq-safe locks: 24
hardirq-unsafe locks: 176
softirq-safe locks: 53
softirq-unsafe locks: 137
irq-safe locks: 59
irq-unsafe locks: 176
The lock validator has observed 1598 actual single-thread locking patterns,
and has validated all possible 2033928 distinct locking scenarios.
More details about the design of the lock validator can be found in
Documentation/lockdep-design.txt, which can also found at:
http://redhat.com/~mingo/lockdep-patches/lockdep-design.txt
[bunk@stusta.de: cleanups]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-07-03 09:24:50 +02:00
|
|
|
#ifdef CONFIG_LOCKDEP
|
|
|
|
/*
|
|
|
|
* Lockdep wants atomic interrupt handlers:
|
|
|
|
*/
|
2007-02-14 09:33:16 +01:00
|
|
|
irqflags |= IRQF_DISABLED;
|
[PATCH] lockdep: core
Do 'make oldconfig' and accept all the defaults for new config options -
reboot into the kernel and if everything goes well it should boot up fine and
you should have /proc/lockdep and /proc/lockdep_stats files.
Typically if the lock validator finds some problem it will print out
voluminous debug output that begins with "BUG: ..." and which syslog output
can be used by kernel developers to figure out the precise locking scenario.
What does the lock validator do? It "observes" and maps all locking rules as
they occur dynamically (as triggered by the kernel's natural use of spinlocks,
rwlocks, mutexes and rwsems). Whenever the lock validator subsystem detects a
new locking scenario, it validates this new rule against the existing set of
rules. If this new rule is consistent with the existing set of rules then the
new rule is added transparently and the kernel continues as normal. If the
new rule could create a deadlock scenario then this condition is printed out.
When determining validity of locking, all possible "deadlock scenarios" are
considered: assuming arbitrary number of CPUs, arbitrary irq context and task
context constellations, running arbitrary combinations of all the existing
locking scenarios. In a typical system this means millions of separate
scenarios. This is why we call it a "locking correctness" validator - for all
rules that are observed the lock validator proves it with mathematical
certainty that a deadlock could not occur (assuming that the lock validator
implementation itself is correct and its internal data structures are not
corrupted by some other kernel subsystem). [see more details and conditionals
of this statement in include/linux/lockdep.h and
Documentation/lockdep-design.txt]
Furthermore, this "all possible scenarios" property of the validator also
enables the finding of complex, highly unlikely multi-CPU multi-context races
via single single-context rules, increasing the likelyhood of finding bugs
drastically. In practical terms: the lock validator already found a bug in
the upstream kernel that could only occur on systems with 3 or more CPUs, and
which needed 3 very unlikely code sequences to occur at once on the 3 CPUs.
That bug was found and reported on a single-CPU system (!). So in essence a
race will be found "piecemail-wise", triggering all the necessary components
for the race, without having to reproduce the race scenario itself! In its
short existence the lock validator found and reported many bugs before they
actually caused a real deadlock.
To further increase the efficiency of the validator, the mapping is not per
"lock instance", but per "lock-class". For example, all struct inode objects
in the kernel have inode->inotify_mutex. If there are 10,000 inodes cached,
then there are 10,000 lock objects. But ->inotify_mutex is a single "lock
type", and all locking activities that occur against ->inotify_mutex are
"unified" into this single lock-class. The advantage of the lock-class
approach is that all historical ->inotify_mutex uses are mapped into a single
(and as narrow as possible) set of locking rules - regardless of how many
different tasks or inode structures it took to build this set of rules. The
set of rules persist during the lifetime of the kernel.
To see the rough magnitude of checking that the lock validator does, here's a
portion of /proc/lockdep_stats, fresh after bootup:
lock-classes: 694 [max: 2048]
direct dependencies: 1598 [max: 8192]
indirect dependencies: 17896
all direct dependencies: 16206
dependency chains: 1910 [max: 8192]
in-hardirq chains: 17
in-softirq chains: 105
in-process chains: 1065
stack-trace entries: 38761 [max: 131072]
combined max dependencies: 2033928
hardirq-safe locks: 24
hardirq-unsafe locks: 176
softirq-safe locks: 53
softirq-unsafe locks: 137
irq-safe locks: 59
irq-unsafe locks: 176
The lock validator has observed 1598 actual single-thread locking patterns,
and has validated all possible 2033928 distinct locking scenarios.
More details about the design of the lock validator can be found in
Documentation/lockdep-design.txt, which can also found at:
http://redhat.com/~mingo/lockdep-patches/lockdep-design.txt
[bunk@stusta.de: cleanups]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-07-03 09:24:50 +02:00
|
|
|
#endif
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* Sanity-check: shared interrupts must pass in a real dev-ID,
|
|
|
|
* otherwise we'll have trouble later trying to figure out
|
|
|
|
* which interrupt is which (messes up the interrupt freeing
|
|
|
|
* logic etc).
|
|
|
|
*/
|
2006-07-02 04:29:31 +02:00
|
|
|
if ((irqflags & IRQF_SHARED) && !dev_id)
|
2005-04-17 00:20:36 +02:00
|
|
|
return -EINVAL;
|
2008-08-20 05:50:14 +02:00
|
|
|
|
2008-08-20 05:50:17 +02:00
|
|
|
desc = irq_to_desc(irq);
|
2008-08-20 05:50:14 +02:00
|
|
|
if (!desc)
|
2005-04-17 00:20:36 +02:00
|
|
|
return -EINVAL;
|
2008-08-20 05:50:14 +02:00
|
|
|
|
2008-08-20 05:50:05 +02:00
|
|
|
if (desc->status & IRQ_NOREQUEST)
|
2006-06-29 11:24:49 +02:00
|
|
|
return -EINVAL;
|
2009-08-13 12:17:22 +02:00
|
|
|
|
|
|
|
if (!handler) {
|
|
|
|
if (!thread_fn)
|
|
|
|
return -EINVAL;
|
|
|
|
handler = irq_default_primary_handler;
|
|
|
|
}
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-02-22 23:00:32 +01:00
|
|
|
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
|
2005-04-17 00:20:36 +02:00
|
|
|
if (!action)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
action->handler = handler;
|
2009-03-23 18:28:15 +01:00
|
|
|
action->thread_fn = thread_fn;
|
2005-04-17 00:20:36 +02:00
|
|
|
action->flags = irqflags;
|
|
|
|
action->name = devname;
|
|
|
|
action->dev_id = dev_id;
|
|
|
|
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_lock(irq, desc);
|
2008-10-16 09:55:00 +02:00
|
|
|
retval = __setup_irq(irq, desc, action);
|
2009-08-13 12:17:48 +02:00
|
|
|
chip_bus_sync_unlock(irq, desc);
|
|
|
|
|
2008-08-21 20:58:28 +02:00
|
|
|
if (retval)
|
|
|
|
kfree(action);
|
|
|
|
|
2007-02-12 09:52:00 +01:00
|
|
|
#ifdef CONFIG_DEBUG_SHIRQ
|
2009-04-01 19:06:35 +02:00
|
|
|
if (!retval && (irqflags & IRQF_SHARED)) {
|
2007-02-12 09:52:00 +01:00
|
|
|
/*
|
|
|
|
* It's a shared IRQ -- the driver ought to be prepared for it
|
|
|
|
* to happen immediately, so let's make sure....
|
2008-08-21 20:58:28 +02:00
|
|
|
* We disable the irq to make sure that a 'real' IRQ doesn't
|
|
|
|
* run in parallel with our fake.
|
2007-02-12 09:52:00 +01:00
|
|
|
*/
|
2007-08-31 08:56:34 +02:00
|
|
|
unsigned long flags;
|
2007-02-12 09:52:00 +01:00
|
|
|
|
2008-08-21 20:58:28 +02:00
|
|
|
disable_irq(irq);
|
2007-08-31 08:56:34 +02:00
|
|
|
local_irq_save(flags);
|
2008-08-21 20:58:28 +02:00
|
|
|
|
2007-08-31 08:56:34 +02:00
|
|
|
handler(irq, dev_id);
|
2008-08-21 20:58:28 +02:00
|
|
|
|
2007-08-31 08:56:34 +02:00
|
|
|
local_irq_restore(flags);
|
2008-08-21 20:58:28 +02:00
|
|
|
enable_irq(irq);
|
2007-02-12 09:52:00 +01:00
|
|
|
}
|
|
|
|
#endif
|
2005-04-17 00:20:36 +02:00
|
|
|
return retval;
|
|
|
|
}
|
2009-03-23 18:28:15 +01:00
|
|
|
EXPORT_SYMBOL(request_threaded_irq);
|