中断控制

1. /proc/interrupts

该文件存放系统中,与中断相关的统计信息。内容如下:

xxha@fast-server02:~$ cat /proc/interrupts
           CPU0       CPU1
  0:        202        727   IO-APIC-edge      timer
  1:          3          1   IO-APIC-edge      i8042
  4:          1          1   IO-APIC-edge
  7:          0          0   IO-APIC-edge      parport0
  8:          1          0   IO-APIC-edge      rtc0
  9:          0          0   IO-APIC-fasteoi   acpi
 12:          5          1   IO-APIC-edge      i8042
 16:     259714        167   IO-APIC-fasteoi   uhci_hcd:usb3, HDA Intel
 17:          9         18   IO-APIC-fasteoi   uhci_hcd:usb4, uhci_hcd:usb7
 18:          0          0   IO-APIC-fasteoi   uhci_hcd:usb8
 22:          0          3   IO-APIC-fasteoi   ehci_hcd:usb1, uhci_hcd:usb5
 23:          0          0   IO-APIC-fasteoi   ehci_hcd:usb2, uhci_hcd:usb6
 24:   25457621          0  HPET_MSI-edge      hpet2
 25:          0    5019320  HPET_MSI-edge      hpet3
 32:    2849638       1889   PCI-MSI-edge      ahci
 33:         59   10112204   PCI-MSI-edge      eth0
 34:     337311     341370   PCI-MSI-edge      fglrx[0]@PCI:1:0:0
NMI:          0          0   Non-maskable interrupts
LOC:        658        635   Local timer interrupts
SPU:          0          0   Spurious interrupts
PMI:          0          0   Performance monitoring interrupts
PND:          0          0   Performance pending work
RES:     506371     494539   Rescheduling interrupts
CAL:       2763       2849   Function call interrupts
TLB:    1062330    1032721   TLB shootdowns
TRM:          0          0   Thermal event interrupts
THR:          0          0   Threshold APIC interrupts
MCE:          0          0   Machine check exceptions
MCP:        830        830   Machine check polls
ERR:          1
MIS:          0
第1列是中断号。

第2,3列是各个CPU接收到的中断个数。

第4列是处理这个中断的中断控制器。如 IO-APIC-edge。

最后一列是与这个中断相关的设备的名字, 这个名字通过参数 devname 传给 request_irq().

如果中断时共享的(如中断16,17等),则这个中断号上注册的所有设备都会列出来。

2. 中断控制

Linux内核提供了一组用于控制机器上中断状态的接口。

这些接口能禁止当前处理器的中断系统,或屏蔽掉整个机器的一个中断号的能力。

锁可以防止其他处理器的并发访问,禁止中断可以防止其他中断处理程序的并发访问。

2.1 禁止和激活当前处理器上的本地中断

local_irq_disable();

//禁止中断区

local_irq_enable();

在产生中断的处理器上,他们将禁止或激活中断的传递。

下面两个函数会更加可靠:

unsigned long flags;

local_irq_save(flags);

//禁止中断区
local_irq_restore(flags);
禁止中断之前保存系统的中断状态,激活中断时恢复原来的中断状态。

local_irq_save(flags) 和 local_irq_restore(flags) 必须在同一个函数中进行。

2.2 禁止指定的中断号

在某些情况下,只需要禁止系统中某一个中断号就够了,这就是所谓的屏蔽一个中断号(masking out)。

void disable_irq(unsigned int irq);  //等待该函数处理内容完成,再返回

void disable_irq_nosync(unsigned int irq);  //不等待

禁止中断控制器上指定的中断号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_to_desc(irq);

	if (!desc)
		return;

	disable_irq_nosync(irq);
	if (desc->action)
		synchronize_irq(irq);
}
EXPORT_SYMBOL(disable_irq);

/**
 *    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_to_desc(irq);
    unsigned long flags;

    if (!desc)
        return;

    chip_bus_lock(desc);
    raw_spin_lock_irqsave(&desc->lock, flags);
    __disable_irq(desc, irq, false);
    raw_spin_unlock_irqrestore(&desc->lock, flags);
    chip_bus_sync_unlock(desc);
}
EXPORT_SYMBOL(disable_irq_nosync);
void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
{
	if (suspend) {
		if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
			return;
		desc->status |= IRQ_SUSPENDED;
	}

	if (!desc->depth++) {
		desc->status |= IRQ_DISABLED;   //声明IRQ_DISABLE
		desc->irq_data.chip->irq_disable(&desc->irq_data);
	}
}
具体的操作在__diable_irq()中完成。
void synchronize_irq(unsigned int 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_to_desc(irq);
	unsigned int status;

	if (!desc)
		return;

	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. */
		raw_spin_lock_irqsave(&desc->lock, flags);
		status = desc->status;
		raw_spin_unlock_irqrestore(&desc->lock, flags);

		/* Oops, that failed? */
	} while (status & IRQ_INPROGRESS);

	/*
	 * 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));
}
EXPORT_SYMBOL(synchronize_irq);
void enable_irq(unsigned int 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 only when
 *	desc->irq_data.chip->bus_lock and desc->chip->bus_sync_unlock are NULL !
 */
void enable_irq(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);
	unsigned long flags;

	if (!desc)
		return;

	if (WARN(!desc->irq_data.chip || !desc->irq_data.chip->irq_enable,
	    KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
		return;

	chip_bus_lock(desc);
	raw_spin_lock_irqsave(&desc->lock, flags);
	__enable_irq(desc, irq, false);
	raw_spin_unlock_irqrestore(&desc->lock, flags);
	chip_bus_sync_unlock(desc);
}
EXPORT_SYMBOL(enable_irq);
void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
{
	if (resume)
		desc->status &= ~IRQ_SUSPENDED;

	switch (desc->depth) {
	case 0:
 err_out:
		WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
		break;
	case 1: {
		unsigned int status = desc->status & ~IRQ_DISABLED;

		if (desc->status & IRQ_SUSPENDED)
			goto err_out;
		/* Prevent probing on this irq: */
		desc->status = status | IRQ_NOPROBE;
		check_irq_resend(desc, irq);
		/* fall-through */
	}
	default:
		desc->depth--;
	}
}

这几个函数可以在中断上下文,或进程上下文中调用,不会睡眠。

禁止多个中断处理程序共享的中断号是不合适的,禁止了该中断号就是禁止了该中断号上的所有设备的中断传递。

3. 查询中断系统状态:

irq_disabled();   --- 如果本地中断被禁止,则返回非0, 否则返回0

in_interrupt();  --- 如果CPU出在中断上下文中,则返回非0,如果在进程上下文中则返回0。

若返回非0, 则说明内核正在执行中断处理程序,或中断下半部处理程序。

in_irq(); --- 如果正在执行中断处理程序,则返回非0,否则返回0.

/*
 * Are we doing bottom half or hardware interrupt processing?
 * Are we in a softirq context? Interrupt context?
 * in_softirq - Are we currently processing softirq or have bh disabled?
 * in_serving_softirq - Are we currently processing softirq?
 */
#define in_irq()		(hardirq_count())
#define in_softirq()		(softirq_count())
#define in_interrupt()		(irq_count())
#define in_serving_softirq()	(softirq_count() & SOFTIRQ_OFFSET)
#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
				 | NMI_MASK))
#define preempt_count()	(current_thread_info()->preempt_count)









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值