[Fw]初探linux中断系统(1)
1. 重要接口
LDD上说,“内核维护了一个中断信号线的注册表,该注册表类似于I/O端口的注册表。模块在使用中断前要先请求一个中断通道(或者中断请求IRQ),然后在使用后释放该通道。”
撇开系统如何遍历各个设备进行初始化,上面两句话说的实际上就是指两个接口函数:
externint __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, constchar*name, void*dev);
externvoid free_irq(unsigned int, void*);
顾名思义,以上两个函数分别用于申请和释放IRQ。
而再一看,会发现其实request_irq是个“皮包”函数,它的定义是这样的:
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
constchar*name, void*dev)
{
return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
所以实际上起到申请IRQ作用的,正是这个request_threaded_irq函数。一查,它位于/kernel/irq/manage.c中。
2.追随request_threaded_irq
先贴上request_threaded_irq全文

int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
constchar*devname, void*dev_id)
{
struct irqaction *action;
struct irq_desc *desc;
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 & IRQF_SHARED) &&!dev_id)
return-EINVAL; desc = irq_to_desc(irq);
if (!desc)
return-EINVAL; if (desc->status & IRQ_NOREQUEST)
return-EINVAL; if (!handler) {
if (!thread_fn)
return-EINVAL;
handler = irq_default_primary_handler;
} action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return-ENOMEM; action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id; chip_bus_lock(irq, desc);
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(irq, desc); if (retval)
kfree(action); #ifdef CONFIG_DEBUG_SHIRQ
if (!retval && (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 disable the irq to make sure that a 'real' IRQ doesn't
* run in parallel with our fake.
*/
unsigned long flags; disable_irq(irq);
local_irq_save(flags); handler(irq, dev_id); local_irq_restore(flags);
enable_irq(irq);
}
#endif
return retval;
}

可以看到除去一些验证的语句,整个函数主要完成的任务是初始化了一个irqaction类型的struct和一个irq_desc类型的struct,接着对这两个struct进一步赋值和处理,便实现了IRQ申请。至此,我们有理由认为这两个struct是kernel管理IRQ的核心数据结构。因此不妨看看他们都是什么样的。

struct irq_desc {
unsigned int irq;
struct timer_rand_state *timer_rand_state;
unsigned int*kstat_irqs;
#ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu;
#endif
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
struct msi_desc *msi_desc;
void*handler_data;
void*chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned long last_unhandled; /* Aging timer for unhandled count */
unsigned int irqs_unhandled;
raw_spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_var_t affinity;
conststruct cpumask *affinity_hint;
unsigned int node;
#ifdef CONFIG_GENERIC_PENDING_IRQ
cpumask_var_t pending_mask;
#endif
#endif
atomic_t threads_active;
wait_queue_head_t wait_for_threads;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
constchar*name;
} ____cacheline_internodealigned_in_smp;

irq_desc实际是个用于构成数组的数据结构。这里irq就是我们熟悉的irq号,每个设备申请到一个IRQ,就需要填充一个irq_desc,并由kernel放入所维护的数组中进行管理。在这些需要填充的内容里,irq_chip和irqaction是两个比较有助于理解数据结构的struct。

struct irq_chip {
constchar*name;
unsigned int (*startup)(unsigned int irq);
void (*shutdown)(unsigned int irq);
void (*enable)(unsigned int irq);
void (*disable)(unsigned int irq);
void (*ack)(unsigned int irq);
void (*mask)(unsigned int irq);
void (*mask_ack)(unsigned int irq);
void (*unmask)(unsigned int irq);
void (*eoi)(unsigned int irq);
void (*end)(unsigned int irq);
int (*set_affinity)(unsigned int irq,
conststruct cpumask *dest);
int (*retrigger)(unsigned int irq);
int (*set_type)(unsigned int irq, unsigned int flow_type);
int (*set_wake)(unsigned int irq, unsigned int on);
void (*bus_lock)(unsigned int irq);
void (*bus_sync_unlock)(unsigned int irq);
/* Currently used only by UML, might disappear one day.*/
#ifdef CONFIG_IRQ_RELEASE_METHOD
void (*release)(unsigned int irq, void*dev_id);
#endif
/*
* For compatibility, ->typename is copied into ->name.
* Will disappear.
*/
constchar*typename;
};

这个struct里主要定义了硬件层面上一个系统对一个IRQ的管理接口。

struct irqaction {
irq_handler_t handler;
unsigned long flags;
constchar*name;
void*dev_id;
struct irqaction *next;
int irq;
struct proc_dir_entry *dir;
irq_handler_t thread_fn;
struct task_struct *thread;
unsigned long thread_flags;
};

这个struct中handler定义了中断处理函数, *next指向了下一个irqaction,也就是说irqaction是以链表的形式存在的。也就是说,每一个IRQ对应一个irq_desc,而irq_desc维护着irq_chip管理了硬件层面的中断使能,同时irq_desc也维护了一个irqaction链表。
根据所查的资料,实际上,系统在处理一个中断时,会根据中断号调用irq_desc数组中的handle_irq, handle_irq再使用chip控制硬件的使能,接着调用irqaction链表,逐个调用中断处理函数。
回过头来,request一个IRQ的过程实际上就是构造irqaction项,free的过程就是移除不需要的irqaction项。
http://www.cnblogs.com/garychen2272/archive/2011/02/25/1964176.html
[Fw]初探linux中断系统(1)的更多相关文章
- [Fw]初探linux中断系统(2)
初探linux中断系统(2) 中断系统初始化的过程 用来初始化中断系统的函数位于arch/x86/kernel/irqinit.c,定义如下 void __init init_IRQ(void){ i ...
- linux中断系统那些事之----中断处理过程【转】
转自:http://blog.csdn.net/xiaojsj111/article/details/14129661 以外部中断irq为例来说明,当外部硬件产生中断时,linux的处理过程.首先先说 ...
- linux中断子系统:中断号的映射与维护初始化mmap过程
本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前沿: 好久好久没有静下心来整理一些东西了 ...
- Linux中断(interrupt)子系统之一:中断系统基本原理【转】
转自:http://blog.csdn.net/droidphone/article/details/7445825 这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于AR ...
- Linux中断(interrupt)子系统之一:中断系统基本原理
这个中断系列文章主要针对移动设备中的Linux进行讨论,文中的例子基本都是基于ARM这一体系架构,其他架构的原理其实也差不多,区别只是其中的硬件抽象层.内核版本基于3.3.虽然内核的版本不断地提升,不 ...
- 裸板中中断异常处理,linux中断异常处理 ,linux系统中断处理的API,中断处理函数的要求,内核中登记底半部的方式
1.linux系统中的中断处理 1.0裸板中中断异常是如何处理的? 以s5p6818+按键为例 1)按键中断的触发 中断源级配置 管脚功 ...
- [fw]LINUX中断描述符初始化
LINUX中断描述符初始化 @CopyLeft by ICANTH,I Can do ANy THing that I CAN THink!~ Author: WenHui, WuHan Univer ...
- 初探Linux内核中的内存管理
Linux内核设计与实现之内存管理的读书笔记 初探Linux内核管理 内核本身不像用户空间那样奢侈的使用内存; 内核不支持简单快捷的内存分配机制, 用户空间支持? 这种简单快捷的内存分配机制是什么呢? ...
- linux中断与异常
看了<深入理解linux内核>的中断与异常,简单总结了下,如果有错误,望指正! 一 什么是中断和异常 异常又叫同步中断,是当指令执行时由cpu控制单元产生的,之所以称之为异常,是因为只有在 ...
随机推荐
- 在css里如何控制表单中文本的value内的文字的位置,比方说让它向右移动2px
方法1:比较简单的方法是将文本放到一个容器中(div,span,a等等)然后给容器设置样式,通过控制容器的位置来达到控制字体位置.(margin-left:10px; margin-top:15px; ...
- Kvm--03 kvm克隆,桥接网络,热添加
目录 1.Kvm克隆 1). 完整克隆 2). 链接克隆 2.kvm虚拟机的桥接网络 3.在线热添加网卡,cpu 1). 热添加网卡 2). 热添加内存 3). 热添加cpu参数 1.Kvm克隆 1) ...
- Codeforces Round #392 (Div. 2) - C
题目链接:http://codeforces.com/contest/758/problem/C 题意:给定N*M矩阵的教室,每个位置都有一个学生,Sergei坐在[X,Y],然后老师会问K个问题,对 ...
- how to pass variable from shell script to sqlplus
script sqlplus ${ORA_USR}/${ORA_PASS}@${ORA_DB} @${PARM}/TEST $new_usr $model_usr $new_pwd parm of s ...
- 【串线篇】加谈数据库之连接join
主题:内连接.左连接(左外连接).右连接(右外连接) 建表语句: CREATE TABLE `a_table` ( `a_id` int(11) DEFAULT NULL, `a_name` va ...
- 网络编程和并发:1.简述 OSI 七层协议
1. 概念 Open System Interconnection : 开放互联系统 2. 图示 注:图片来源:https://www.cnblogs.com/maybe2030/p/4781555. ...
- Oracle RAC常用命令
Oracle Clusterware的命令集可以分为以下4种,其中用的最多的是crsctl和srvctl:节点层:osnodes olsnodes -n -i -s olsnodes -l -p 网络 ...
- Mybatis原理及源码分析
什么是Mybatis? Mybatis是一个半自动化的持久层框架. Mybatis可以将向PreparedStatement中的输入参数自动进行映射(输入映射),将结果集映射成Java对象(输出映射) ...
- 输入流之顶层抽象InputStream
该类是所有二进制输入流的的抽象父类 类中主要方法解释说明如下 (1)public abstract int read() throws IOException; 该方法是从输入流中读取下一个字节,返回 ...
- Angular JS - 8 - SeaJS与前端模块化
一.前端模块化 关于前端模块化,参考以下链接 : https://github.com/seajs/seajs/issues/547 http://www.cnblogs.com/huiguo/cat ...