三读内核中断处理(5):中断系统提供的API

快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

本文适用于

ADSP-BF561

优视BF561EVB开发板

uclinux-2008r1.5-rc3(smp patch)

Visual DSP++ 5.0(update 5)

欢迎转载,但请保留作者信息

中断系统提供的API大都在kernel/irq/manage.c中。

1.1 synchronize_irq

这个函数用于在两个核间进行中断的同步:

/**

* synchronize_irq - wait for pending IRQ handlers (on other CPUs)

* @irq: interrupt number to wait for

*

* 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)

{

struct irq_desc *desc = irq_desc + irq;

if (irq >= NR_IRQS)

return;

while (desc->status & IRQ_INPROGRESS)

cpu_relax();

}

这个函数仅用于使用SMP的情况。由于每一个核都可以同等地处理每一个外部中断,因此有时候需要进行同步,从代码可以看出,它就是简单地等待一个中断处理完成。

1.2 disable_irq_nosync

这个函数用于关闭指定中断:

/**

* 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)

{

struct irq_desc *desc = irq_desc + irq;

unsigned long flags;

if (irq >= NR_IRQS)

return;

spin_lock_irqsave(&desc->lock, flags);

if (!desc->depth++) {

desc->status |= IRQ_DISABLED;

desc->chip->disable(irq);

}

spin_unlock_irqrestore(&desc->lock, flags);

}

可以看出,这个函数直接调用irq_chip的成员disable这一回调函数,野蛮的关闭硬件中断!

1.3 disable_irq

这个函数将关闭硬件中断并等待(可能有的)中断处理完成。

/**

* 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)

{

struct irq_desc *desc = irq_desc + irq;

if (irq >= NR_IRQS)

return;

disable_irq_nosync(irq);

if (desc->action)

synchronize_irq(irq);

}

1.4 enable_irq

这个函数用于启用一个指定的中断。

/**

* 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.

*

* This function may be called from IRQ context.

*/

void enable_irq(unsigned int irq)

{

struct irq_desc *desc = irq_desc + irq;

unsigned long flags;

if (irq >= NR_IRQS)

return;

spin_lock_irqsave(&desc->lock, flags);

switch (desc->depth) {

case 0:

printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);

WARN_ON(1);

break;

case 1: {

unsigned int status = desc->status & ~IRQ_DISABLED;

/* Prevent probing on this irq: */

desc->status = status | IRQ_NOPROBE;

check_irq_resend(desc, irq);

/* fall-through */

}

default:

desc->depth--;

}

spin_unlock_irqrestore(&desc->lock, flags);

}

在系统初始化完成的时候,每个irq_desc->depth值都将初始化为1。因而这个函数将直接执行check_irq_resend启用中断。

1.5 free_irq

这个函数用于释放中断:

/**

* free_irq - free an interrupt

* @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)

{

struct irq_desc *desc;

struct irqaction **p;

unsigned long flags;

irqreturn_t (*handler)(int, void *) = NULL;

WARN_ON(in_interrupt());

if (irq >= NR_IRQS)

return;

desc = irq_desc + irq;

spin_lock_irqsave(&desc->lock, flags);

p = &desc->action;

for (;;) {

struct irqaction *action = *p;

if (action) {

struct irqaction **pp = p;

p = &action->next;

if (action->dev_id != dev_id)

continue;

/* Found it - now remove it from the list of entries */

*pp = action->next;

/* Currently used only by UML, might disappear one day.*/

#ifdef CONFIG_IRQ_RELEASE_METHOD

if (desc->chip->release)

desc->chip->release(irq, dev_id);

#endif

if (!desc->action) {

desc->status |= IRQ_DISABLED;

if (desc->chip->shutdown)

desc->chip->shutdown(irq);

else

desc->chip->disable(irq);

}

spin_unlock_irqrestore(&desc->lock, flags);

unregister_handler_proc(irq, action);

/* Make sure it's not being used on another CPU */

synchronize_irq(irq);

if (action->flags & IRQF_SHARED)

handler = action->handler;

kfree(action);

return;

}

printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);

spin_unlock_irqrestore(&desc->lock, flags);

return;

}

#ifdef CONFIG_DEBUG_SHIRQ

if (handler) {

/*

* It's a shared IRQ -- the driver ought to be prepared for it

* to happen even now it's being freed, so let's make sure....

* We do this after actually deregistering it, to make sure that

* a 'real' IRQ doesn't run in parallel with our fake

*/

handler(irq, dev_id);

}

#endif

}

1.6 request_irq

这个函数用以自己指定一个中断的处理函数。

/**

* request_irq - allocate an interrupt line

* @irq: Interrupt line to allocate

* @handler: Function to be called when the IRQ occurs

* @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.

*

* 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:

*

* IRQF_SHARED Interrupt is shared

* IRQF_DISABLED Disable local interrupts while processing

* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy

*

*/

int request_irq(unsigned int irq, irq_handler_t handler,

unsigned long irqflags, const char *devname, void *dev_id)

{

struct irqaction *action;

int retval;

#ifdef CONFIG_LOCKDEP

/*

* Lockdep wants atomic interrupt handlers:

*/

irqflags |= IRQF_DISABLED;

#endif

/*

* 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).

*/

if ((irqflags & IRQF_SHARED) && !dev_id)

return -EINVAL;

if (irq >= NR_IRQS)

return -EINVAL;

if (irq_desc[irq].status & IRQ_NOREQUEST)

return -EINVAL;

if (!handler)

return -EINVAL;

action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

if (!action)

return -ENOMEM;

action->handler = handler;

action->flags = irqflags;

cpus_clear(action->mask);

action->name = devname;

action->next = NULL;

action->dev_id = dev_id;

select_smp_affinity(irq);

#ifdef CONFIG_DEBUG_SHIRQ

if (irqflags & IRQF_SHARED) {

/*

* It's a shared IRQ -- the driver ought to be prepared for it

* to happen immediately, so let's make sure....

* We do this before actually registering it, to make sure that

* a 'real' IRQ doesn't run in parallel with our fake

*/

if (irqflags & IRQF_DISABLED) {

unsigned long flags;

local_irq_save(flags);

handler(irq, dev_id);

local_irq_restore(flags);

} else

handler(irq, dev_id);

}

#endif

retval = setup_irq(irq, action);

if (retval)

kfree(action);

return retval;

}

这里直接用kmalloc来分配irqaction其实挺浪费空间的。当然由于中断个数有限,其浪费的空间数量也有限,呵呵。

你可能感兴趣的:(Blog,UP,UML)