首页 理论教育深入剖析TI芯片中断处理实现

深入剖析TI芯片中断处理实现

【摘要】:接下来分步说明中断处理的具体实现。Linux内核irqdesc.h中有如下定义:这里可见宏NR_IRQS描述了所有中断的个数,这个数目应该是和处理器相关的。具体的级联中断的解决办法留到相应模块中进行详细说明。3中断控制器的处理接下来看看DM 3730的内核是如何实现中断控制器的管理的。图4-30引自《DM 3730芯片手册》中第2411页的框图。电源管理没有中断控制器唤醒的相关实现,由于这部分是在ARM主处理器的电源域中,并不需要这部分功能。

首先来看看DM 3730中断控制器的框架,如图4-29所示。图4-29引自《DM 3730芯片手册》中第2406页的框图。

978-7-111-49426-3-Chapter04-118.jpg

图4-29 DM 3730中断控制器框图

从图4-29可见,中断控制器的时钟等信号是在PRCM的管理之下,所以相应的也有电源管理的功能,后续的代码注释中对相关的代码进行了说明。但是由于电源管理的框架还没有进行介绍,所以中断控制器中相关电源管理的代码可以先浏览,等到了解电源管理框架之后会有更加深入的理解。

接下来分步说明中断处理的具体实现。

1ᤫ中断号实现

从图4-29中可见,中断控制器有96个中断,这些中断号是如何定义的,又如何让系统知道正确的中断数目的呢?

Linux内核irqdesc.h中有如下定义:

978-7-111-49426-3-Chapter04-119.jpg

这里可见宏NR_IRQS描述了所有中断的个数,这个数目应该是和处理器相关的。DM3730上NR_IRQS的具体值以及中断号的定义在arch/arm/plat-omap/include/mach/irqs.h中可见,具体如下:

978-7-111-49426-3-Chapter04-120.jpg

这里为什么不是96的数值,而是另外的一个宏呢?其实这是为了解决中断级联的问题。之前在框架设计中已经看到,通过irq_action可以解决中断共享,但是并没有说明如何解决中断级联。其实中断级联就是通过irq_desc自身解决的,比如GPIO做中断源的话就会产生级联中断的情况,这样中断号就需要增加,就像需求中讨论的某些中断号(如INT_34XX_GPIO_BANKx)会作为特殊中断来进行处理,在Linux内核中,是通过set_irq_chained_han-dler来实现该功能的。注意DM 3730内核不支持配置CONFIG_SPARSE_IRQ,所以不能用动态申请的方式支持级联,而只能采用静态扩大中断号的方式。具体的级联中断的解决办法留到相应模块中进行详细说明。

2ᤫARM向量表到中断处理的实现

ARM内核的中断处理是从向量表开始的。向量表在arch/arm/kernel/entry_armv.S中定义:

978-7-111-49426-3-Chapter04-121.jpg

978-7-111-49426-3-Chapter04-122.jpg

这部分代码主要分为两部分:其一是真正的向量表,位于_vectors_start和_vectors_end之间;其二是处理跳转的部分,位于_stubs_start和_stubs_end之间。

978-7-111-49426-3-Chapter04-123.jpg

这句其实是宏把宏展开后就定义了vector_irq。根据进入中断前的处理器模式,分别跳转到_irq_usr或_irq_svc。

978-7-111-49426-3-Chapter04-124.jpg

这句宏展开后就定义了vector_dabt,根据进入中断前的处理器模式,分别跳转到_dabt_usr或_dabt_svc。

在系统启动阶段,由early_trap_init()(位于arch/arm/kernel/traps.c中)初始化向量表的过程如下:

978-7-111-49426-3-Chapter04-125.jpg

以上两个memcpy会把_vectors_start开始的代码复制到0xffff0000处,把_stubs_start开始的代码复制到0xffff0000+0x200处,和相对跳转的偏移相同。这样异常中断到来时,CPU就可以正确地跳转到相应中断向量入口并执行了。

为什么要将_stubs_start开始的内容进行如此的复制呢?这里说明一下,先看看内核编译后的符号表:

978-7-111-49426-3-Chapter04-126.jpg

可见stubs_start在向量表内容之前,而根据向量处理的映射,整个向量处理的代码都需要在0xffff0000之后的一个页内,所以就需要将_stubs_start开始的内容进行复制,这也是需要进行偏移修正的原因。

对于中断使用vector_stub方式如下:

978-7-111-49426-3-Chapter04-127.jpg

进一步分析vector_stub:

978-7-111-49426-3-Chapter04-128.jpg(www.chuimin.cn)

中断处理上述代码,最终会根据之前的模式进入_irq_usr或者_irq_svc执行,二者最终都会进入irq_handler这个宏:

978-7-111-49426-3-Chapter04-129.jpg

get_irqnr_preamble和get_irqnr_and_base这两个宏由板级支持的代码在arch/arm/plat-omap/include/mach/entry-macro.S中定义,目的就是从中断控制器中获得正确的中断号,来看看相应的实现:

978-7-111-49426-3-Chapter04-130.jpg

978-7-111-49426-3-Chapter04-131.jpg

978-7-111-49426-3-Chapter04-132.jpg

从这可见,无论DM 3730、TI 816X还是OMAP4都有自己的实现,其中比较重要的是宏OMAPx_IRQ_BASE,这是中断控制器的基地址,get_irqnr_preamble就是通过该宏获得中断控制器的基地址的。而get_irqnr_and_base也需要该基地址来获得正确的触发中断的中断号。在irq_handler获得正确的中断号之后,紧接着就调用asm_do_IRQ,从这个函数开始,中断程序进入C代码中。该函数在arch/arm/kernel/irq.c中,实现如下:

978-7-111-49426-3-Chapter04-133.jpg

到这里,中断处理就完成了从向量表到体系结构无关的generic_handle_irq中断处理的转换,后续可以根据正确的中断号进行中断处理了。

3ᤫ中断控制器的处理

接下来看看DM 3730的内核是如何实现中断控制器的管理的。首先,看一下DM 3730中断控制器的内部框架,如图4-30所示。图4-30引自《DM 3730芯片手册》中第2411页的框图。

978-7-111-49426-3-Chapter04-134.jpg

图4-30 DM 3730中断控制器内部框架

从图4-30中可见,该中断控制器可进行中断的优先级管理,并能屏蔽中断,以及伪中断的检查,这些都是内核需要的中断控制器的功能。DM 3730中断控制器的实现代码在linux/arch/arm/mach-omap2/irq.c中。中断控制器的管理主要是实现irq_chip的操作接口,该接口提供给内核的中断处理框架,通过这些接口,内核可在其提供的标准中断处理流程接口irq_flow_handler_t中调用如ack、mask、unmask等操作,从而正确完成整个的中断处理流程。现将中断控制器管理相关的代码整理到一起,并注释如下:

978-7-111-49426-3-Chapter04-135.jpg

978-7-111-49426-3-Chapter04-136.jpg

978-7-111-49426-3-Chapter04-137.jpg

978-7-111-49426-3-Chapter04-138.jpg

4ᤫ中断控制器初始化

中断控制器初始化相关的代码和具体实现说明如下:

978-7-111-49426-3-Chapter04-139.jpg

978-7-111-49426-3-Chapter04-140.jpg

978-7-111-49426-3-Chapter04-141.jpg

5ᤫ电源管理相关

最后来看看电源管理相关的代码,先对模块的电源管理有个初步的了解。

978-7-111-49426-3-Chapter04-142.jpg

978-7-111-49426-3-Chapter04-143.jpg

978-7-111-49426-3-Chapter04-144.jpg

电源管理没有中断控制器唤醒的相关实现,由于这部分是在ARM主处理器的电源域中,并不需要这部分功能。会由其他的部分来唤醒系统。