此间少年,老于此间
分类:
2015-09-18 16:21:56
、PPR、APR和Lowest priority —— 中断发给Whom?
RTE的delivery mode有一中模式为lowest priority,即最低优先级,它是Linux配置RTE时使用的模式。这里的最低优先级不是指中断的优先级,而是指将中断发送给destination field列出的CPU中,优先级最低的一个。如何决定一个CPU的优先级呢?x86平台依靠TPR寄存器和PPR寄存器。
TPR,task priority register,任务优先级寄存器,它确定当前CPU可处理什么优先级别范围内的中断。具有如下的格式:
图1-10 TPR寄存器 TPR寄存器接收0~15共16个值,对应16个CPU规定的中断优先级级别,值越大优先级越高。CPU只处理比TPR中值优先级别更高的中断。例如TPR中值为8,则级别小于等于8的中断被屏蔽(注意,屏蔽不代表拒绝,LAPIC接收它们,把它们pending到IRR中,但不交CPU处理。见前面LAPIC中断处理流程)。值15表示屏蔽所有中断;值0表示接收所有中断,噢,这也是Linux为TPR设置的默认值。注意,TPR是由软件读/写的,硬件不更改它。 的中断优先级级别 我们知道每个中断都有一个vector与之对应,x86平台共有256个vector,除去架构预留和被异常等占去的0~31号vector,可供外部中断使用的还有224个(噢,实际上只有223个,还要除去一个INT 80)。中断的优先级别由下列公式: 优先级别 = vector / 16 这里“/”是c语言的除,不是数学里的除号,所以我们是没有小数的。16~255号vector构成了1~15共15个优先级别,中断拥有2~15级别。对于同一个级别的中断,vector号越大的优先级越高。例如vector33、34都属于级别2,34的优先级就比33高。所以,对于8bit的vector,又可以划分成两部分,高4bit表示中断优先级别,低4bit表示该中断在这一级别中的位置。 噢,应该讲清楚了,记住,TPR的值增加1,将会屏蔽16个vector对应的中断。NMI、SMI、ExtINT、INIT、start-up delivery的中断不受TPR约束。 笔者:TPR,任务优先级寄存器 ,很容易的就让人和进程的优先级联想到一起。实际上,x86的spec也强调这里的“Task”代表操作系统中的进程、线程、任务、程序 ……不过,Linux的进程优先级和它没有关系。如果Linux的中断处理例程线程化了,如果Linux具有更强的实时性,如果Linux跟着Windows、Solaris学习,如果 …… Linux或许会把它和进程优先级挂上勾。现在嘛,Linux没有那样做。不过,APIC设计TPR的目的,真是给Task用的,期望进程切换时也会更新TPR值,这是APIC的历史文档告诉我们的。 TPR为8bit组成,从图中我们可以看到,0~15这16个值应该写到高4bit去。如果我们同时也写了低4bit会怎么样?从关于TPR的论述来看,CPU会忽略低4bit的值。 PPR,Processor priority register,处理器优先级寄存器。该寄存器决定当前CPU正在处理的中断的优先级级别,以确定一个Pending在IRR上的中断是否发送给CPU。与TPR不同,它的值由CPU写而不是软件写。PPR取值范围为[0,15],计算方式由下列伪代码描述: If TPR[7:4] >= ISR[7:4] THEN PPR[7:0] = TPR[7:0] ELSE PPR[7:4] = ISRV[7:4] PPR[3:0] = 0 这里,ISRV[7:4]标识当前ISR中,最高优先级中断对应vector的高4bit,如前面所说,这代表了该中断的优先级级别。简而言之,取TPR和正在服务的最高优先级中断中,优先级级别高的。好了,都知道了,IRR中pending的中断,优先级级别必须高于PPR中值才会被发送给CPU处理,否则,继续等 …… 谁是Lowest Priority? 有了前面两个寄存器的论述,现在可以看看Lowest Priority是怎么决定的了。先来从Pentium4和Xeon系列说吧,它们要简单点(实际上更复杂,但因为资料少,我可以说的简单点。具体信息?去看mindshare那本讲前端总线的书吧,2000多页的英文读本) 对于这个系列,LAPIC和IOAPIC通过前端总线通讯。X86 spec对这个描述是:“芯片组负责从destination filed列出的CPU中,选出一个优先级最低的接收中断。如果是Pentium4,CPU会用一个特殊的总线周期(bus cycle)将每个CPU当前的任务优先级提交到总线,芯片组记录它们,并作为挑选最低优先级CPU的依据”。完了,够简单吧^_^ 笔者:从spec来看,无论是Xeon还是Pentium4,都是由芯片组选最低优先级CPU。依据是什么?spec讲的不清楚。但对于pentium4,提到了“用一个特殊的bus cycle将当前各CPU的task priority提交到总线”。这个task priority具体指什么?spec也没说。但在TPR相关章节中有这么一句话:“注意,task priority用于决定CPU的仲裁优先级(见8.6.2.4,Lowest Priority Delivery Mode)”。虽然没有明说,但我们有理由认为,这里的task priority就是TPR的值。 P6架构的系统,依靠一个APR寄存器(Arbitration Priority Register,优先级仲裁寄存器)决定CPU优先级,其格式如图1-11:
图1-11 APR寄存器 APR值可由下列伪代码计算: If ( (TPR[7:4] >= IRRV[7:4]) && (TPR[7:4] > ISRV[7:4]) ) APR[7:0] = TPR[7:0] Else { APR[7:4] = max(TPR[7:4],IRRV[7:4],ISRV[7:4]) APR[3:0] = 0 } 上述代码表述了这么一个意思:当TRP的值大于IRR中最高优先级中断的优先级级别,并大于ISR中最高优先级中断的优先级级别时,APR等于TPR。否则,APR高4bit取TPR、IRRV、ISRV三者中优先级级别最高的;低4bit取0 对于P6架构和Pentium系列CPU,spec提到了一个Focus Processor的概念。如果一个中断A正在被某CPU1处理,或者pending在CPU1的IRR上,则称CPU1为中断A的Focus Processor。当系统中有Focus Processor存在时,Focus Processor可能(may)接收该中断,不管自身的优先级是多少。Xeon系列没有Focus Processor的概念。 笔者:关于Focus Processor是尽量按spec的原话翻译,当然,E文水平有限,翻译的不好。不过大概就是这个意思。Focus Processor在哪儿设定?伪中断寄存器(见后面的伪中断相关内容)。spec说:“If a focus processor exists, it may accept the interrupt, regardless of its priority”,spec用了一个may。这种不清不楚的用词太万恶了,让人完全搞不清楚它什么时候会may,什么时候又may not。不管怎样,Focus Processor给了我们这样一种暗示,即当系统中大量产生同一种中断时,该中断会被发送给同一个CPU处理。这样的好处是可以避免cache颠簸,缺点也十分明显:运行在该CPU上的进程可能饿死、中断处理过慢、系统中断负载不平衡 …… 我们又注意到,Xeon系列取消了这个功能,应该是顺应民心吧。既然已经有了PRT表,CPU就不应该再提供这种重定向中断的功能。 发了一堆牢骚,其实情况没那么糟糕。Focus Processor只对edge触发中断有效。而目前平台上大量使用的PCI是level触发的。为什么?想想Focus Processor的定义,再去看看前面关于同类型中断pending两次的说明吧。 我们来举一个Pentium4和Xeon系列优先级仲裁的例子,说明谁是Lowest Priority。假设有CPU1、CPU2、CPU3三个CPU,相应的TPR值为:TPR1=5、TPR2=6、TPR3=10,IOAPIC以lowest priority模式发送一条中断消息,该中断对应的优先级级别为3。则CPU1具有最低优先级,接收该中断。此时,该中断被pending到IRR中,但不会交给CPU处理,因为其优先级级别低于TPR值。 至此,IOAPIC和LAPIC相互配合的中断机制已经大体介绍完了,其中提到了一部分寄存器和它们的功用。APIC的其它内容在后面分析Linux实现时补充,一次把硬件内容写完,你看着烦,我写着也累,而且逻辑容易乱。