免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: albcamus

level, edge, cli, disable_irq, PIT, LAPIC Timer ... 一次讨论个清楚吧! [复制链接]

论坛徽章:
0
发表于 2008-03-28 15:54 |显示全部楼层
原帖由 bluesky_jxc 于 2008-3-28 15:31 发表
EOI表示中断服务完成
ACK表示cpu希望中断控制器下一个周期发送中断向量。。。。。

关键是ACK会屏蔽当前产生中断的line,在中断完时还有一个应答re-enable这条line。
我想这个就是和EOI最大的区别。
也就是说PIC是两次应答,IOAPIC是一次应答

论坛徽章:
0
发表于 2008-03-28 16:24 |显示全部楼层
( A ) PIC中,有三个比较重要的寄存器,中断请求IRR,中断服务ISR,屏蔽MASK。

PIC最开始的设计,
IRR相当于一个锁存器,来一个电压跳变锁存一次,将IRR对应位置1。这步无视MASK,也无视当前中断优先级。
在ISR根据自身优先级以及MASK,判断出更高优先级中断到来,于是取走IRR里的向量,同时IRR相应位置0。这步与MASK相关,也与ISR里的当前优先级相关。

因此,MASK是影响的PIC里的仲裁机制,而并不是彻底屏蔽这个中断线。当MASK的中断,或者低优先级中断发生时,虽然不能处理这个中断,但是IRR还是会把它保存起来,将来UNMASK时,仲裁机制会看到这个被保存起来的IRQ,并且ISR会取走它,相当于IRQ_REPLAY。

由于IRR这种硬件机制的存在,8259在disable_irq时,直接设置MASK,不需耍任何花样。

不过这只是个简单的锁存器,并没有FIFO的功能,来100个不能处理的中断,也只保存了一个。




到了APIC,有了些变化,屏蔽是彻底的屏蔽了中断线,而不是只影响仲裁机制。

对于level,这没有什么问题,即使屏蔽了中断线,电平也会自动保持住。等unmask时,IO-APIC还会看到这个电平,还会经由Local APIC,把它发给CPU。这也相当于IRQ_REPLAY。于是在disable_irq时,也是直接mask,而没有花招。

但对于edge,就有了问题。屏蔽中断线后,跳变总不会自己保持,又无法象PIC一样,硬件可以自动保存这个IRQ。所以必须以软件手段来模拟一下IRR的行为。

因此,disable_irq并不是真正的屏蔽中断线,而只是记一个IRQ_DISABLE标志位,中断照常发生并传递给CPU。随后,发生中断时,CPU在do_IRQ中,又记一个IRQ_PENDING,然后再真正屏蔽这个中断线。

这样,8259中硬件实现,由IRR来保存的中断号,到了APIC里,由软件来实现,记录在irq_desc_t里的IRQ_PENDING位。在unmask时,发现了IRQ_PENDING位,通过IPI,来IRQ_REPLAY一次。

论坛徽章:
0
发表于 2008-03-28 16:39 |显示全部楼层
原帖由 motalelf 于 2008-3-28 16:24 发表 [
因此,disable_irq并不是真正的屏蔽中断线,而只是记一个IRQ_DISABLE标志位,中断照常发生并传递给CPU。


其他地方能理解, 这句总觉得不对。


disable_irq() > disable_irq_nosync() :

desc->status |= IRQ_DISABLED;
desc->chip->disable(irq);


而我们考虑一个 外设上的中断, 它的chip是ioapic_chip, 其disable方法为mask_IO_APIC_irq (注:ioapic_chip并没有disable方法,按照irq_chip结构的注释,如果disable为NULL,那么就会默认为其mask方法):

mask_IO_APIC_irq >  __mask_IO_APIC_irq


/* mask = 1 */
static void __mask_IO_APIC_irq (unsigned int irq)
{
        __modify_IO_APIC_irq(irq, 0x00010000, 0);
}

0x00010000, 正好是把IO-APIC中这个irq 的entry的 第16比特设置为1 ── 也就是mask。  这个见82093AA datasheet

        struct IO_APIC_route_entry {
                        __u32        vector                :  8,
                                delivery_mode        :  3,        /* 000: FIXED
                                                         * 001: lowest prio
                                                         * 111: ExtINT
                                                         */
                                dest_mode        :  1,        /* 0: physical, 1: logical */
                                delivery_status        :  1,
                                polarity        :  1,
                                irr                :  1,
                                trigger                :  1,        /* 0: edge, 1: level */
                                mask                :  1,        /* 0: enabled, 1: disabled */
                                __reserved_2        : 15;

                        union {                struct { __u32
                                                        __reserved_1        : 24,
                                                        physical_dest        :  4,
                                                        __reserved_2        :  4;
                                        } physical;

                                        struct { __u32
                                                        __reserved_1        : 24,
                                                        logical_dest        :  8;
                                        } logical;
                        } dest;

                } __attribute__ ((packed));
          

       


所以我觉得您这里说的有问题

论坛徽章:
0
发表于 2008-03-28 16:42 |显示全部楼层
MSI确实不懂,但从它的形式就可以看出来只能是edge触发,因为它是设备直接在总线上发消息给LAPIC,那么这就是个瞬态行为,符合edge的性质(当然,edge有效电平的建立需要一段时间,不过这个是题外话了)


老大,这句太精彩了!!

论坛徽章:
0
发表于 2008-03-28 16:57 |显示全部楼层
原帖由 zx_wing 于 2008-3-28 12:16 发表
最近正在认真学习这个部分,al老大就发起话题了,正好也讨论一下

1 )level 和 edge这两种类型的中断, 谁能简要的说一下区别?   

   附加疑问: 为什么MSI中断被当成edge中断?

区别嘛,汗 ...



SPURIOUS INTERRUPT正在看, 非常感谢提醒。 (此前看到8.7节就停下了

今天抽空想看看HPET、PIT和LAPIC Timer, 发现clock event机制抽象的太厉害, 几乎没法跟踪……

论坛徽章:
0
发表于 2008-03-28 17:01 |显示全部楼层
原帖由 motalelf 于 2008-3-28 16:24 发表
( A ) PIC中,有三个比较重要的寄存器,中断请求IRR,中断服务ISR,屏蔽MASK。

PIC最开始的设计,
IRR相当于一个锁存器,来一个电压跳变锁存一次,将IRR对应位置1。这步无视MASK,也无视当前中断优先级。
...


对于这一段论述,我认为有几个问题。
1.CPU在do_IRQ中,又记一个IRQ_PENDING,然后再真正屏蔽这个中断线
这个是在说PIC吗?如果是PIC,我认为不存在这个问题,因为PIC不会在一个中断未处理完时又来一个同样的中断。如果是IOAPIC,那么记一个IRQ_PENDING也不会去屏蔽中断线。
IRQ_PENDING表示该中断已经应答,但还没处理。对于IOAPIC来说,既然应答了,那就允许继续产生中断。

2. APIC也有IRR,APIC在LAPIC中,SAPIC在IOSAPIC上。没有看到kernel有什么软件方法来模拟IRR,这个希望塑料袋兄再解释一下。

3. IRQ_REPLAY和IRQ_PENDING的配合使用主要是为了处理lost interrput,也就是当一个CPU在处理某类型的中断,另一个CPU屏蔽了该中断。当处理中断的的CPU遇到IRQ_DISABLE标志从而导致应答中断但还没处理就返回了。所以在irq_enable时会检查是否有这种lost interrupt进而处理掉。这在ULK的4.6节有专门的章节论述。

4. 此外,如al版主所说,APIC状态下,disable_irq会修改RTE而屏蔽中断

论坛徽章:
0
发表于 2008-03-28 17:12 |显示全部楼层

回复 #16 zx_wing 的帖子

这个IRQ_REPLAY所补偿的, 完全是Linux内核的软件设计导致的 中断丢失, 和硬件没关系。  ULK3上讲得很详细,我和塑料袋说了,丫愣是不信……

论坛徽章:
0
发表于 2008-03-28 17:52 |显示全部楼层
我觉得如某device产生了中断,不论是否屏蔽,或迟或早,必须要得到处理,不然这个device就瘫了。

mask时,既然不希望处理,那么就只能推迟。推迟到unmask时,重现一次中断发生时的情景。

对于level,由于电平的保持,中断一直在产生,不需要附加手段,就能重现。

但是对于edge,线上的跳变既然不能一直跳下去,则必须IPI来模拟中断发生时的情景。但是这条线到底需不需要模拟中断发生时的情景呢?也许在mask的期间,一直没有中断过。所以kernel必须有个依据,判断这个线是否中断过。

这个依据,在PIC中是IRR,硬件自动重现了中断发生时的情景。

在APIC中,虽然local APIC有IRR,但是IO-APIC没有。

对于已mask的中断线,如果IO-APIC也能注意到这个中断,并把中断号发给Local APIC,使用Local APIC的IRR将它保存起来,这样当然最好。

但是IO-APIC不会这样做,它完全忽略mask的中断线。

如果disable_irq中,直接将IO-APIC的LVT屏蔽的话,以后,即使这条中断线上产生中断,也无迹可寻。在unmask时,kernel根本不知道这条线是否发生过中断。这时就两难。

REPLAY的话,可能线根本没有中断过,中断服务程序所做的处理,不仅可能得到错误的结果,还可能干扰正常的命令序列 。
不REPLAY的话,设备就一直不会再产生中断,一直瘫下去。

论坛徽章:
0
发表于 2008-03-28 18:43 |显示全部楼层
原帖由 motalelf 于 2008-3-28 17:52 发表
我觉得如某device产生了中断,不论是否屏蔽,或迟或早,必须要得到处理,不然这个device就瘫了。

mask时,既然不希望处理,那么就只能推迟。推迟到unmask时,重现一次中断发生时的情景。

对于level,由于 ...

PCI明确规定设备必须是level触发,IOAPIC上只有pit是edge触发。
我对timer不太了解,但记忆中timer中断是有可能丢失造成tick lost的

论坛徽章:
0
发表于 2008-03-28 20:29 |显示全部楼层
关于edge触发中断的内容,我又调查了一下,最近的kernel确实提供了一个和塑料袋兄说的类似的机制来防止edge中断丢失。
见下:
Delayed interrupt disable
This per interrupt selectable feature, which was introduced by Russell King in the ARM interrupt implementation, does not mask an interrupt at the hardware level when disable_irq() is called. The interrupt is kept enabled and is masked in the flow handler when an interrupt event happens. This prevents losing edge interrupts on hardware which does not store an edge interrupt event while the interrupt is disabled at the hardware level. When an interrupt arrives while the IRQ_DISABLED flag is set, then the interrupt is masked at the hardware level and the IRQ_PENDING bit is set. When the interrupt is re-enabled by enable_irq() the pending bit is checked and if it is set, the interrupt is resent either via hardware or by a software resend mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when you want to use the delayed interrupt disable feature and your hardware is not capable of retriggering an interrupt.) The delayed interrupt disable can be runtime enabled, per interrupt, by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP