我眼中的Linux设备树(四 中断)

四 中断

中断一般包括中断产生设备和中断处理设备。中断控制器负责处理中断,每一个中断都有对应的中断号及触发条件。中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中的一个中断,这种情况中断产生设备的中断源称之为中断控制器中对应中断的子中断。一般情况中断产生设备数量要多于中断控制器,多个中断产生设备的中断都由一个中断控制器处理,这种多对一的关系也很像一个树形结构,所以在设备树中,中断也被描述成树,叫中断树。以下表述的时候为了明确是在说中断树,在父节点和子节点前边我们都加上“中断”二字,是为了防止和设备树的父节点、子节点混淆(虽然大部分情况设备树的父子关系就是中断树的父子关系,但是因为存在特例,所以我们还是强调是中断父子关系)。

中断产生设备用interrupts属性描述中断源(interrupt specifier),因为不同的硬件描述中断源需要的数据量不同,所以interrupts属性的类型也是<prop-encoded-array>。为了明确表示一个中断由几个u32表示,又引入了#interrupt-cells属性,#interrupt-cells属性的类型是u32,假如一个中断源需要2个u32表示(一个表示中断号,另一个表示中断类型),那么#interrupt-cells就设置成2。有些情况下,设备树的父节点不是中断的父节点(主要是中断控制器一般不是父节点),为此引入了interrupt-parent属性,该属性的类型是<phandle>,用来引用中断父节点(我们前边说过,一般用父节点的标签,这个地方说中断父节点而不是中断控制器是有原因的)。如果设备树的父节点就是中断父节点,那么可以不用设置interrupt-parent属性。interrupts属性和interrupt-parent属性都是中断产生设备节点的属性,但是#interrupt-cells属性不是,#interrupt-cells属性是中断控制器节点以及interrupt nexus节点的属性,这两类节点都可能是中断父节点。

中断控制器节点用interrupt-controller属性表示自己是中断控制器,这个属性的类型是空,不用设置值,只要存在这个节点就表示该节点是中断控制器。除了这个属性外,中断控制器节点还有#interrupt-cells属性,用来表示该中断控制器直接管理下的interrupt domain(后边我们会讲中断控制器的中断子节点interrupt nexus节点有单独的interrupt domain)用几个u32表示一个中断源(interrupt specifier)。中断控制器节点就包括interrupt-controller和#interrupt-cells两个关于中断的属性。中断控制器的#address-cells属性和中断映射有关系,但是该属性不是为中断设计的,中断映射只是用到了这个属性而已。

前边说中断控制器中的一个中断可能对应中断产生设备中的多个中断源,那这种对应关系用什么描述呢?我们还说过#interrupt-celll属性不仅是中断控制器节点的属性,还是interrupt nexus节点的属性,这个interrupt nexus节点就是描述中断映射关系的,该节点通过interrupt-map,interrupt-map-mask属性描述中断映射关系。interrupt-map属性是<prop-encoded-array>类型的,每个元素表示一个中断映射关系(注意是一个"中断映射关系",不是"一个中断"映射关系),从前向后包括:中断子设备地址,中断子设备中断源(interrupt specifier),中断父设备,中断父设备地址,中断父设备中断源(interrupt specifier)五部分。中断子设备地址具体由几个u32组成是由中断子设备所在总线(不是中断父设备)的#address-cells属性决定的,这个地方为什么用中断设备地址而不用中断设备的phandle,是有原因的,因为中断设备会用interrupt-parrent属性指向中断父节点,所以中断子设备是可以确定的,不需要说明。还因为中断子设备地址可以做与运算,通过interrupt-map-mask属性就可以实现多对一的映射。中断子设备中断源(interrupt specifier)由几个u32组成是由该interrupt nexus节点下的#interrupt-cell决定的。中断父设备是一个指向中断父设备的<phandle>属性,一般情况下是中断控制器,但是按照中断树的逻辑,也可能是更高一级的interrupt nexus节点。中断父设备地址具体由几个u32组成是由中断父设备节点下的#address-cells属性决定的(注意,不是中断父设备所在总线的#address-cells属性)。中断父设备中断源(interrupt specifier)由几个u32组成是由中断父设备的#interrupt-cells属性决定的。

还记得前边说过中断设备的中断源和中断控制器的中断源可能是多对一的关系,如果每个子中断都用interrupt-map中的一行表示,那么interrupt-map属性将非常大。为了让多个子中断共享映射关系,引入了interrupt-map-mask属性,该属性的类型也是<prop-enacoded-array>,包含中断子设备地址和中断子设备中断源的bit mask,给定一个子中断源,那么首先和interrupt-map-mask做与运算,运算结果再通过interrupt-map属性查找对应的中断父设备中断源。这就是我们前边为什么说interrupt-map属性的一行是一个“中断映射关系”,而不是“一个中断”映射关系的原因。

我们再来复习一下,整个中断树的最底层是中断产生设备(也可能是从interrupt nexus节点),中断产生设备用interrupts属性描述他能产生的中断。因为他的中断父设备可能和设备树的父设备不同,那么用interrupt-parent属性指向他的中断父设备。他的中断父设备可能是中断控制器(如果中断产生设备的中断和中断控制器的中断是一一对应的,或者最底层是interrupt nexus节点),也可能是interrupt nexus节点(如果最底层是中断产生设备,且需要映射)。interrupt nexus节点及他的所有直接子节点构成了一个interrupt domain,在该interrupt domain下中断源怎样表示由#interrupt-cells属性决定,如何由中断子设备中断源找到中断父设备中断源由interrupt-map和interrupt-map-mask属性决定。interrupt nexus的父节点可能还是一个interrupt nexus父节点,也可能是一个中断控制器,当向上找到最后一个中断控制器,并且该中断控制器再也没有中断父设备时,整个中断树就遍历完成了。中断控制器用interrupt-controller属性表示自己是中断控制器,并且用#interrupt-cells属性表示他所直接管理的interrupt domain用几个u32表示一个中断源。根据中断树的特性,一个设备树中是有可能有多个中断树的。

以上是中断在设备树中如何描述的规则,听起来是挺复杂的,但只要理解了就很简单,为了帮助理解我们举一个实际的例子。为了突出中断部分,我们做了简化。
/ {
    model = "Marvell Armada 375 family SoC";
    compatible = "marvell,armada375";
    soc {
        #address-cells = <2>;
        #size-cells = <1>;
        interrupt-parent = <&gic>;

internal-regs {
            compatible = "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;

[email protected] {
                compatible = "arm,cortex-a9-twd-timer";
                reg = <0xc600 0x20>;
                interrupts = <GIC_PPI 13 (IRQ_TYPE_EDGE_RISING | GIC_CPU_MASK_SIMPLE(2))>;
                clocks = <&coreclk 2>;
            };

gic: [email protected] {
                compatible = "arm,cortex-a9-gic";
                #interrupt-cells = <3>;
                #address-cells = <0>;
                interrupt-controller;
                reg = <0xd000 0x1000>,
                      <0xc100 0x100>;
            };
        }

pcie-controller {
            compatible = "marvell,armada-370-pcie";
            #address-cells = <3>;
            #size-cells = <2>;

[email protected],0 {
                #address-cells = <3>;
                #size-cells = <2>;
                #interrupt-cells = <1>;
                interrupt-map-mask = <0 0 0 0>;
                interrupt-map = <0 0 0 0 &gic GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
            };
        };
}

首先我们看到[email protected]这个设备节点下定义了interrupts属性,这说明该设备可以产生中断,但是这个属性下描述了几个中断我们是看不出来的(如果有经验了,我们能猜出只是一个中断,现在我们按照规则确认)。因为该节点没有interrupt-parent属性,那么认为设备树的父节点internal-regs就是中断父节点,在internal-regs父节点下还是没有interrupt-parent属性,那么还是继续找设备树父节点,找到了soc,在该节点下边有interrupt-parent属性。该属性引用的标签为gic,搜索整个设备树,[email protected]的标签为gic。gic节点下有interrupt-controller属性,说明他是一个中断控制器。gic节点还有属性#interrupt-cells = <3>,说明在该控制器的interrupt domain下,中断源(interrupt specifier)用3个u32表示,我们再看[email protected]下的interrupts属性也确实由3个u32组成(可以参考GIC的规范,第一个u32表示中断类型,第二个是中断号,第三个是中断触发条件)。这个例子说明如果中断产生设备的中断源和中断控制器的中断源是一一对应的,那么可以不需要interrupt nexus节点及相关的属性来表示中断映射。

再看[email protected],0这个节点,有#interrupt-cells属性,但是没有interrupt-controller属性,这说明他是一个interrupt nexus节点。该节点的#interrupt-cells属性为1,说明该interrupt nexus节点管辖下的中断源用1个u32表示就可以了。在[email protected],0节点下边没有子节点,且也没有节点的interrupt-parent属性指向[email protected],0节点,所以从设备树上看不到该interrupt domain下的中断产生设备,可能的原因是这些中断产生设备软件可以动态识别所以不需要设备树描述。因为interrupt-map-mask属性是由中断产生设备的地址和中断源(interrupt specifier)组成,且中断源用1个u32表示,那么可以推测中断产生设备地址由3个u32组成。这里需要注意的是[email protected],0节点的#address-cells属性为3,是说该总线下边的设备地址用3个u32表示,但并不代表中断产生设备的设备地址也一定3个u32表示,此处不能说是巧合,但是我们要清楚中断产生设备的地址由几个u32组成是由该设备所在总线决定的,对于pcie总线也确实是3,但是其他总线可能存在其他种的情况。现在我们来分析interrupt-map属性,前三个数字是中断设备地址,第四个数字是中断设备的中断源。因为interrupt-map-mask是全0,这样不管与什么数字做与运算结果都是0,interrupt-map属性的前4个数字也都是0,这说明在[email protected],0下边所有的中断映射到中断父节点的中断都是一个中断。接着是指向gic的<phandle>,因为gic节点下#address-cells属性为0,所以后边不需要描述中断父设备的地址了,后边3个数字都是表示中断父设备中断源的。一句话描述就是[email protected],0下的所有中断都映射到gic,GIC_SPI类型的第29号中断,触发类型为高电平触发。这个例子说明在中断树的最下边可以是interrupt nexus节点。

以上例子中断树的根是gic,gic下边有两个孩子,一个是中断设备[email protected],一个是interrupt nexus节点[email protected],0。gic直接管辖的interrupt domain用3个u32表示中断源,[email protected]在这个interrupt domain下。[email protected],0下定义了一个新的interrupt domain,在该interrupt domain下,中断源用1个u32表示,[email protected],0用interrupt-map和interrupt-map-mask属性将下边所有设备的中断映射到一个gic下边的中断上。

时间: 2024-10-25 14:21:41

我眼中的Linux设备树(四 中断)的相关文章

Linux设备树(四 中断)

四 中断 中断一般包括中断产生设备和中断处理设备.中断控制器负责处理中断,每一个中断都有对应的中断号及触发条件.中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中的一个中断,这种情况中断产生设备的中断源称之为中断控制器中对应中断的子中断.一般情况中断产生设备数量要多于中断控制器,多个中断产生设备的中断都由一个中断控制器处理,这种多对一的关系也很像一个树形结构,所以在设备树中,中断也被描述成树,叫中断树.以下表述的时候为了明确是在说中断树,在父节点和子节点前边我们都加上"中断"

我眼中的Linux设备树(一 概述)

一 概述 设备树(Device tree)是一套用来描述硬件属相的规则.ARM Linux采用设备树机制源于2011年3月份Linux创始人Linus Torvalds发的一封邮件,在这封邮件中他提倡ARM平台应该参考其他平台如PowerPC的设备树机制描述硬件.因为在此之前,ARM平台还是采用旧的机制,在kernel/arch/arm/plat-xxx目录和kernel/arch/arm/mach-xxx目录下用代码描述硬件,如注册platform设备,声明设备的resource等.因为这些代

我眼中的Linux设备树(二 基础规范概述)

二 基础规范概述 DTS(Device tree syntax,另一种说法是Device tree source)是设备树源文件,为了方便阅读及修改,采用文本格式.DTC(Device tree compiler)是一个小工具,负责将DTS转换成DTB(Device tree blob).DTB是DTS的二进制形式,供机器使用.使用中,我们首先根据硬件修改DTS文件,然后在编译的时候通过DTC工具将DTS文件转换成DTB文件,然后将DTB文件烧写到机器上(如emmc,磁盘等存储介质).系统启动时

我眼中的Linux设备树(三 属性)

三 属性(property) device_type = "memory"就是一个属性,等号前边是属性,后边是值.节点是一个逻辑上相对独立的实体,属性是用来描述节点特性的,根据需要一个节点由0个,1个或多个属性表示节点的特性.一个属性由名字和值两部分组成. 和节点的名字类似,规范要求属性名字由1到31个字符组成.和节点名字字符的种类有些区别,不允许有大写字母,增加了问号和井号两个字符.不清楚为什么没有和节点名字完全保持一致,井号对于初学者容易误解,以为是注释. 0-9    数字a-z

Linux设备树语法详解

Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码.比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的

Linux设备树语法详解【转】

本文转载自:http://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码.比如在AR

zynq基础--&gt;LINUX 设备树

1.概念 linux设备树是用于描述硬件及部分启动指令的文件,由bootloader传递给内核, 内核分析此文件而对硬件使用不同的参数. 比如两块开发板仅仅是内存容量不一样,那么就只需要修改设备树中对内存容量的描述即可, 而不需要重新编译内核. 与设备树相关的文件有如下几种: DTS(device tree source) .dts文件,就是ASCII字符串形式的文本文件,直接由开发人员修改. 对于ARM架构而言,这些文件位于:arch/arm/boot/dts 目录下. DTSI(device

迅为iTOP-iMX6开发板-设备树内核-中断例程

1.1 中断概述 ARM 架构 linux 内核中,有 5 种常见的异常,其中中断异常是其一,Linux 内核将所 有中断统一编号,使用一个 irq_desc 结构体来描述这些中断,里面记录了中断名称.中断状 态.中断标记.并提供了中断的底层硬件访问函数(如:清除.屏蔽.使能中断),提供了这 个中断的处理函数入口,通过它还可以调用用户注册的的中断处理函数.linux 内核的中断体 系已经很完善了,驱动工程师需要做的就是调用 request_irq 函数向内核注册中断处理函 数,下面我们来看看 r

Linux设备树使用(二)

一.设备树与驱动的匹配1.设备树会被/scripts中的dtc可执行程序编译成二进制.dtb文件,之前设备树中的节点信息会以单链表的形式存储在这个.dtb文件中:驱动与设备树中compatible属性匹配上后, 驱动中的相应的node节点就映射在这个设备树节点上了,然后以这个node为参数调用of函数来解析这个设备树块上的信息为驱动所用.设备树中的信息是逐条进行获取的(?) 2.例如设备树中有如下定义: flash_SY7803:flashlight { compatible = "qcom,l