Interrupt Handling [LDD3 10]

尽管device的IO region可以用来控制device,但是还不够。一个device,往往会有外界有交互,当外界发生了某个事件,需要device做出某种响应,driver也需要做处理。CPU不可能一直等device的某个event,而应该在event发生时,由device通知CPU。因此那就要有一种机制,让device能够通知到driver,这就是中断的作用。

所谓中断,就是硬件在需要CPU做出反应的时候发出的signal,kernel处理硬件中断的方式方法和user space处理signal是类似的。

driver能做的,其实就是实现一个interrupt handler,并注册给kernel,当device中断产生时,handler能够正确处理这个中断就可以了。在讲中断之前,需要强调一点,interrupt handler是和其他的code并发运行的,因此handler里一定要考虑竞争和并发的问题。

10.1. Preparing the Parallel Port


准备并口设备这里不讲了,因为没有并口设备。

10.2. Installing an Interrupt Handler


如果想在device driver中接收并处理设备产生的中断,得需要device driver告诉kernel怎么把中断传递给driver。如果没有匹配的handler,设备的中断会被忽略。

中断线(interrupt line)是kernel里很宝贵又很稀有的资源,一共只有15/16个,driver在使用中断之前要申请中断线资源,使用完后释放。在很多情况下,kernel中有些module driver可能要与别的drivershare同样的中断线。

获取中断资源的函数:

<linux/interrupt.h>
int request_irq(unsigned int irq, 
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
                unsigned long flags,
                const char *dev_name,
                void *dev_id);

void free_irq(unsigned int irq, void *dev_id);

request_irq的返回值,如果是0,表明成功,如果返回负值,说明获取irq失败。下面是参数的说明:

unsigned int irq : driver请求的设备中断号

irqreturn_t (*handler)(int, void *, struct pt_regs *) : 中断发生时用来处理中断的handler

unsigned long flags  : 和中断管理相关的一些bitmask,包含SA_INTERRUPT,SA_SHIRQ,SA_SAMPLE_RANDOM,在下面会详细说明。

const char *dev_name  : 中断的owner,设备名字,在/proc/interrupts下会显示。

void *dev_id : 对于shared  interrupt line有用。一般是device的structure,或者一些private data,用来表明是谁的中断。如果不是shared interrupt line,可以设为NULL。

关于参数flags,有SA_INTERRUPT,SA_SHIRQ,SA_SAMPLE_RANDOM这几种:

SA_INTERRUPT: 如果设这个flag,说明是一个Fast的handler,Fast的handler运行的时候会关闭当前CPU的中断。

SA_SHIRQ:如果设这个flag,说明中断可以在设备之间share。

SA_SAMPLE_RANDOM: 如果你的device产生的中断比较随机,那么可以设这个flag,这样的话,OS上层需要产生随机数的时候,就可以把你的中断作为参考因素之一。

interrupt的handler可以在module driver初始化的时候注册,也可以在device被open的时候注册。LDD3推荐后者,也就是在device被open的时候才注册,因为中断线是有限的资源,有些device driver初始化的时候注册,但是后续可能并不会使用,这就造成了浪费,因此推荐在driver被open的时候才去请求中断,并注册handler。

一般来说,在device被open,但是还没有让device产生中断之前request_irq,在所有的device都被close之后再free_irq,这种方式的缺点在于,需要device driver自己保存device的计数,来确定什么时候关闭了所有的device。

一个使用request_irq的例子:

if (short_irq >= 0) {
    result = request_irq(short_irq, short_interrupt,
            SA_INTERRUPT, "short", NULL);
   if (result) {
        printk(KERN_INFO "short: can't get assigned irq %i\n",
                short_irq);
        short_irq = -1;
    }
    else { /* actually enable it -- assume this *is* a parallel port */
        outb(0x10,short_base+2);
    }
}

有些架构比如X86,有一个query irq是否可用的接口:

int can_request_irq(unsigned int irq, unsigned long flags);

如果irq当前没有人使用,就返回非零值。

10.2.1. The /proc Interface

每当hardware产生中断,并被CPU接收时,kernel就会把中断计数加1,这个计数可以用来check hardware是否正常工作。中断的计数可以通过/proc/interrupts来读取。另外,/proc/stat也可以出去interrupt的数量,区别在于stat里是自系统起来获取的中断数;而/proc/interrupts只统计当前active的中断数。比如这里有一个读取中断计数的例子:

root@montalcino:/bike/corbet/write/ldd3/src/short# m /proc/interrupts
           CPU0       CPU1       
  0:    4848108         34    IO-APIC-edge  timer
  2:          0          0          XT-PIC  cascade
  8:          3          1    IO-APIC-edge  rtc
 10:       4335          1   IO-APIC-level  aic7xxx
 11:       8903          0   IO-APIC-level  uhci_hcd
 12:         49          1    IO-APIC-edge  i8042
NMI:          0          0 
LOC:    4848187    4848186 
ERR:          0
MIS:          0

第一类是中断数IRQ number。从上面可以看出,CPU0一直在处理中断,而CPU1就很少,因为在同一个CPU上处理中断容易缓存命中,有助于提高performance。最后两列,第一个是interrupt controller,以及注册这个中断的设备名字。

从/proc/stat读取的中断信息:

intr 5167833 5154006 2 0 2 4907 0 2 68 4 0 4406 9291 50 0 0

第一个值表示所有中断的总和,后面的每一个都代表一个interrupt line(从0开始)。这里统计的是所有曾经产生的中断,即便你的device被关闭了,这里仍然可以看到它之前产生的中断,因此有时候,/proc/stat里的信息要比/proc/interrupts里的更有参考意义。

这两个文件的 另一个区别是:interrupts是与架构无关的,而stat是架构相关的。系统中可用的IRQ line根据架构的不同而不同,比如SPARC上只有16个IRQ line,而在IA-64上则有256个IRQ line。

下面这个是在IA-64上的/proc/interrupts的输出实例:

           CPU0       CPU1       
 27:       1705      34141  IO-SAPIC-level  qla1280
 40:          0          0           SAPIC  perfmon
 43:        913       6960  IO-SAPIC-level  eth0
 47:      26722        146  IO-SAPIC-level  usb-uhci
 64:          3          6   IO-SAPIC-edge  ide0
 80:          4          2   IO-SAPIC-edge  keyboard
 89:          0          0   IO-SAPIC-edge  PS/2 Mous
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值