[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控制单元产生的,之所以称之为异常,是因为只有在 ...
随机推荐
- windows下安装oracle11g
第一步:一定要先做这一步. Oracle11g 安装过程出现提示:未找到文件 D:\app\Administrator\product\11.2.0\dbhome_2\owb\external\oc4 ...
- JS面向对象——动态原型模型、寄生构造模型
动态原型模型 组合使用构造函数模型和原型模型,使得OO语言程序员在看到独立的构造函数和原型时很困惑.动态原型模型致力于解决该问题,它把所有的信息封装在构造函数中,通过在构造函数中初始化原型(仅在必要情 ...
- Beta阶段成果展示——第八组
Beta阶段成果展示 游戏公网IP:http://119.29.32.204/krad.html(欢迎大家测试!) Beta阶段体现在成果上的工作主要为界面美化,玩家引导,按键封闭等等. 本文将以截图 ...
- Linux学习笔记5(2)-CentOS7中Tomcat8修改jvm内存配置
1.进入tomcat的bin目录,比如我的在 /usr/local/apache-tomcat-8.5.16/bin 2.创建新的文件setenv.sh vi setenv.sh 并在此文件中添加以下 ...
- smbspool - 将一个打印文件发送到一台SMB打印机
总览 SYNOPSIS smbspool {job} {user} {title} {copies} {options} [filename] 描述 DESCRIPTION 此程序是Samba(7)套 ...
- skiasharp在阿里云Windows server 2016上部署时提示The type initializer for 'SkiaSharp.SKAbstractManagedStream' threw an exception. 错误
应用环境及问题描述: Windows Server 2016,.Net core 2.1, Skiasharp作为跨平台的图像处理组件在生成缩略图时出错,本地测试都是正常的,部署到服务器无法生成缩略图 ...
- Linux就该这么学06学习笔记
参考链接:https://www.linuxprobe.com/chapter-06.html 1.一切从“/”开始 Linux系统中的一切文件都是从“根(/)”目录开始的,并按照文件系统层次化标准( ...
- python如何获取变量的变量名
假设现在存在一个值为1变量名为a的变量,如何通过一个函数获取该变量的变量名a? 上面这个需求来源于某群友的一个要求,希望能有一个这样的函数来方便打印. 这个需求很扯淡啊,为什么不用格式化输出?它回复到 ...
- Java8 stream基础
List<Integer> list = new ArrayList<Integer>(); list.add(2); list.add(4); list.add(0); li ...
- HttpClient测试框架
HttpClient是模拟Http协议客户端请求的一种技术,可以发送Get/Post等请求. 所以在学习HttpClient测试框架之前,先来看一下Http协议请求,主要看请求头信息. 如何查看HTT ...