- 论坛徽章:
- 0
|
![]()
文件:
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 |
|