免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 838 | 回复: 0
打印 上一主题 下一主题

中断的前因后果 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-10 15:09 |只看该作者 |倒序浏览


文件:
linux中断的前应后果.rar
大小:
13KB
下载:
下载


1           关于本博客
本博客中的文章不会涉及linux的操作层次,我只会一步一步去深入内核。错别字在所难免,瑕不掩瑜。
需要多久的时间才能精通linux内核,网上说需要三年的全职工作,我不对其结论。
但有一点很清楚,如果你决定去学linux,那么你应该把她当作一种宗教信仰,否则难以学会。
本系列至少会出100篇linux内核的文章,由点到线再到面的学习方法,希望能减轻你的学习痛苦。你将在阅读中体会到幽默和乐趣。
一个月,两个月几乎不可以学好,可能要一年。就如本博客名一样“郑钱多多”,如果你学好,年薪会在20万以上。

本博客地址:
http://qianduoduo.cublog.cn
钱多多cublog
讨论邮箱:
loveher147@qq.com
两年内讨论有效。现在时间2009年6月15日

详情请参考我的财富网站:
http://www.goldenkid.com.cn/10money/?10861.htm

欢迎各位访问,算是对我生活的支持,做出更好的网站来。


2           传播许可
任何人都可以用鲜红色,四号黑体字修改本文档,以区别原始文档,并且你应该发一份到邮箱
loveher147@qq.com
,以便作者进一步完善。当然你可以加上你的名字和联系方式,让更多的读者了解你的能力。

详情请参考我的财富网站:
http://www.goldenkid.com.cn/10money/?10861.htm

欢迎各位访问,算是对我生活的支持,做出更好的网站来。




第一章 中断处理... 1
第二章 中断相关的结构... 2
第三章 申请中断... 4
第四章 打开和禁止中断... 7
第五章 中断共享... 8
第六章 中断共享... 8

第一章 中断处理
如果,想看看中断的杂文,那么看看陈利君老师的一篇文章比较好。

例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。因此,内核把中断处理分为两部分:上半部(tophalf)和下半部(bottomhalf),上半部(就是中断服务程序)内核立即执行,而下半部(就是一些内核函数)留着稍后处理,

但是,内核到底什时候执行下半部,以何种方式组织下半部?这就是我们要讨论的下半部实现机制,这种机制在内核的演变过程中不断得到改进,在以前的内核中,这个机制叫做bottomhalf(简称bh),在2.4以后的版本中有了新的发展和改进,改进的目标使下半部可以在多处理机上并行执行,并有助于驱动程序的开发者进行驱动程序的开发。下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。

在/proc/interrupts 中可以看到设备驱动说对应的中断号及类型。
256个中断的使用情况:
0-31 由处理器保留
80 系统调用总入口
15个8259中断。IRQ0-15 映射到0x20-0x2f 中断号。
其他被一些硬件使用,其实用得很少。
重新定义一下
0~31为异常和非屏蔽中断
32~47为可屏蔽中断(硬件中断)
48~255用来表示软中断,Linux只用了其中的一个(即128或0x80向量)作为系统调用。

第二章中断相关的结构
动作结构,中断到来时,要完成的任务。
struct irqaction {
       irqreturn_t (*handler)(int, void *, struct pt_regs *);
       unsigned long flags;
中断类型,快速中断,和正常中断
       cpumask_t mask;
中段屏蔽字
       const char *name;
设备名,中断为设备用
       void *dev_id;

       struct irqaction *next;
指向下一个action,共享IRQ时用。
       int irq;
       struct proc_dir_entry *dir;
};

中断控制描述符
/*
* Interrupt controller descriptor. This is all we need
* to describe about the low-level hardware.
*/
struct hw_interrupt_type {
       const char * typename;
类型名
       unsigned int (*startup)(unsigned int irq);
允许IRQ产生的事件发生

       void (*shutdown)(unsigned int irq);
禁止IRQ产生的事件发生
       void (*enable)(unsigned int irq);
       void (*disable)(unsigned int irq);
       void (*ack)(unsigned int irq);
       void (*end)(unsigned int irq);
       void (*set_affinity)(unsigned int irq, cpumask_t dest);
};

Hw是指hardware

中断描述符结构体,包含各种中断信息。

/*
* This is the "IRQ descriptor", which contains various information
* about the irq, including what kind of hardware handling it has,
* whether it is disabled etc etc.
*
* Pad this out to 32 bytes for cache and indexing reasons.
*/
typedef struct irq_desc {
       hw_irq_controller *handler;  
指向硬件中断类型
       void *handler_data;
       struct irqaction *action; /* IRQ action list */
一般IRQ只联系一个动作,当IRQ被共享时,队列就有多个元素
       unsigned int status;        /* IRQ status */
       unsigned int depth;        /* nested irq disables */
当前用户数目
       unsigned int irq_count;          /* For detecting broken interrupts */
       unsigned int irqs_unhandled;
       spinlock_t lock;
} ____cacheline_aligned irq_desc_t;
相关宏
typedef struct hw_interrupt_type  hw_irq_controller;

第三章申请中断
设备在使用中断请求号时,需要申请。函数是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:
*
*    SA_SHIRQ            Interrupt is shared  可以在设备将共享
*    SA_INTERRUPT          Disable local interrupts while processing 这是一个不接受中断的快速中断
*    SA_SAMPLE_RANDOM      The interrupt can be used for entropy 如果读者的设备以真正的随机的周期产生中断,那么就应该设置这个标志。
*
*/
int request_irq(unsigned int irq,  // 中断号
              irqreturn_t (*handler)(int, void *, struct pt_regs *),  // 函数
              unsigned long irqflags, const char * devname, void *dev_id)  // 用来共享的中断号
{
       struct irqaction * action;
       int retval;

       /*
        * 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 & SA_SHIRQ) && !dev_id)
              return -EINVAL;
       if (irq >= NR_IRQS)
              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;

       retval = setup_irq(irq, action);
       if (retval)
              kfree(action);

       return retval;
}

EXPORT_SYMBOL(request_irq);

将中断加入到全局中断描述结构数组中。如果新旧中断都可以共享,则将新中断加到后面。如果没有使用,则直接加到中断描述符结构数组中,并设置中断使能。
/*
* Internal function to register an irqaction - typically used to
* allocate special interrupts that are part of the architecture.
*/
int setup_irq(unsigned int irq, struct irqaction * new)
{
       struct irq_desc *desc = irq_desc + irq;
       struct irqaction *old, **p;
       unsigned long flags;
       int shared = 0;

       if (desc->handler == &no_irq_type)
              return -ENOSYS;
       /*
        * Some drivers like serial.c use request_irq() heavily,
        * so we have to be careful not to interfere with a
        * running system.
        */
       if (new->flags & SA_SAMPLE_RANDOM) {
              /*
               * 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);
       }

       /*
        * The following block of code has to be executed atomically
        */
       spin_lock_irqsave(&desc->lock,flags);
       p = &desc->action;
       if ((old = *p) != NULL) {
              /* Can't share interrupts unless both agree to */
              if (!(old->flags & new->flags & SA_SHIRQ)) {
                     spin_unlock_irqrestore(&desc->lock,flags);
                     return -EBUSY;
              }

              /* add new interrupt at end of irq queue */
              do {
                     p = &old->next;
                     old = *p;
              } while (old);
              shared = 1;
       }

       *p = new;

       if (!shared) {
              desc->depth = 0;
              desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
                              IRQ_WAITING | IRQ_INPROGRESS);
              if (desc->handler->startup)
                     desc->handler->startup(irq);
              else
                     desc->handler->enable(irq);
       }
       spin_unlock_irqrestore(&desc->lock,flags);

       new->irq = irq;
       register_irq_proc(irq);
       new->dir = NULL;
       register_handler_proc(irq, new);

       return 0;
}

用来查询某个中断线是否可以用
Can_request_irq
注意在调用can后调用request_irq,可能中断线的可用状态已经改变了。


自动探测设备要使用的IRQ号。
有两种情况,现代的设备已经具有了自动定义IRQ的功能,所以如果要得到IRQ号,就去查询设备就可以了。第二种情况,则完全不是,需要程序员自己检测。
Probe_irq_on
Probe_irq_off

第四章打开和禁止中断
Disable_irq   禁止中断,而且会等待当前正在执行的中断处理完成。
Disable_irq_nosync
Enable_irq

启用和禁止特定的IRQ中断信号线。


自动检查iRQ号
unsigned long probe_irq_on(void)
int probe_irq_off(unsigned long val)
第五章中断共享
中断号(线)可以被多个设备使用,中断源。中断触发方式有水平和边缘触发。

水平触发在软件清楚之前会一直保存信号。如果多个设备同时发出信号,cpu会轮训,所以这是安全的。

边缘类型触发则要不安全得多。
Dev_id 必须唯一,代表设备
通过该id可以找到对应的驱动程序。
在共享中一般不会使用enable_irq 和disable_irq





本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/98987/showart_1992004.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP