Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5772058
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: LINUX

2008-08-13 11:40:06

在读e1000代码的时候,分析到中断处理函数。对于NAPI模式跟踪发现,只有在poll函数末尾开中断,但是没有关中断的地方,看注释发现有一个叫做interrupt auto-mask的东西,查了一下intel的手册,分析了一下。

了解几个寄存器的作用:
Interrupt Cause Read Register
ICR (000C0H; R)
这个寄存器包括以太网控制器中所有的中断条件。每次一个中断事件发生的时候,寄存器中相应的中断位(0-19)就会被设置。当每次寄存器中的中断位被设置后,就会生成一个PCIe*中断,
当然需要通过IMS和ITR寄存器的允许才可以发生。

每次中断事件发生后,所有定时器延迟中断被清除,并且他们的事件被设置在ICR寄存器中。
ICR寄存器的读倒错,会有下面的几种可能:
1.中断屏蔽寄存器(IMS)=0000h(全部屏蔽)
  ICR寄存器的内容被清空。
2.中断断言(ICR.INT_ASSERTED = 1b)
  ICR寄存器内容被清空,Auto-Mask被激活(IAM寄存器被写到IMC寄存器)。
3.中断没有断言(ICR.INT_ASSERTED = 0b)
  ICR寄存器不会被清空

向这个寄存器中的任何一位写1,都会清空这个位;向任何一位写0对这一位没有任何影响。INT_ASSERTED位是一个特例,向它写1或0都没有影响。只有在所有的中断源都被清空之后,它才会被清空。
当CPU向量被清空后,第7,16,17位也会被清空。

注意:如果IMS=0b,ICR寄存器总是在读取后自动清除。如果IMS没有被设置为0b,但是一些ICR位被设置但是对应的IMS位没有设置的情况,读取操作不会清空ICR寄存器。
例如,IMS=10101010b ICR=01010101b,读ICR寄存器不会清空它。
     IMS=10101010b ICR=0101011b,读ICR寄存器就会整个的清空它(ICR.INT_ASSERTED=1b)。

INT_ASSERTED:Interrupt Asserted
中断断言位:当网络接口上有一个等待的中断,这个位就会被设置。如果在PCIe*的配置空间里面中断被允许的话,发生一个中断。


Interrupt Mask Set/Read Register
IMS (000D0h; R/W)
当相应的位被设置为1的时候,一个中断被允许;同理设置为0,将会屏蔽一个中断。当这个寄存器中的一个位被设置,并且在相应的中断条件发生的时候,就会产生一个PCIe*中断。中断条件的发生通过设置ICR中相应位。
通过向这个寄存器相应屏蔽位写1来允许一个中断。写0将不会变化。因此,如果想屏蔽一个刚刚允许的中断,需要向IMC寄存器相应位写1,而不是向这个这个寄存器写0。
通过读这个寄存器,可以返回已经设置的中断屏蔽位。


Interrupt Mask Clear Register
IMC (000D8h; W)
可以使用这个寄存器来屏蔽一个中断。中断只有当mask位设置为1并且cause位设置为1的时候,才会提交到总线接口上。mask位在IMS中设置,cause位在ICR中设置。
可以通过清除对应的mask位的方法来屏蔽中断。这可以通过向这个寄存器相应的位写1来实现。如果写0的话,mask位不会发生变化。
为了确保兼容性,我们应当向保留的位也写1。因为当向对应的位写1可以屏蔽中断,向保留位也写1可以确保软件不响应中断。

Interrupt Acknowledge Auto Mask Register
IAM (000E0h; R/W)
每次当CTRL_EXT.IAME被设置,并且ICR.INT_ASSERT为1时,ICR的访问事件会有一个副作用,就是将IAM寄存器的值写到IMC寄存器中。

分析e1000-7.6.5代码:
在e1000_probe中:

    /* Hardware features, flags and workarounds */
    if (adapter->hw.mac.type >= e1000_82571) {
        adapter->flags.int_assert_auto_mask = 1;
#ifdef CONFIG_PCI_MSI
        adapter->flags.has_msi = 1;
#endif
        adapter->flags.has_manc2h = 1;
    }


在e1000_configure_rx中:

    if (hw->mac.type >= e1000_82571) {
        ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
        /* Reset delay timers after every interrupt */
        ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
#ifdef CONFIG_E1000_NAPI /*设置Auto-Mask*/
        /* Auto-Mask interrupts upon ICR access */
        ctrl_ext |= E1000_CTRL_EXT_IAME;
        E1000_WRITE_REG(hw, E1000_IAM, 0xffffffff);
#endif
        E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
        E1000_WRITE_FLUSH(hw);
    }


在e1000_intr中:

#ifdef CONFIG_E1000_NAPI
    /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
     * not set, then the adapter didn't send an interrupt */
    if (adapter->flags.int_assert_auto_mask &&
        !(icr & E1000_ICR_INT_ASSERTED))
        return IRQ_NONE; /*这里出现的这种情况,可能是共享中断导致的,一个非网卡中断进入了这个中断处理函数*/

    /* Interrupt Auto-Mask...upon reading ICR,
     * interrupts are masked.  No need for the
     * IMC write, but it does mean we should
     * account for it ASAP. */
    if (likely(hw->mac.type >= e1000_82571))
        atomic_inc(&adapter->irq_sem);
#endif

......

#ifdef CONFIG_E1000_NAPI
    if (hw->mac.type < e1000_82571) {
        /* disable interrupts, without the synchronize_irq bit */
        atomic_inc(&adapter->irq_sem);
        E1000_WRITE_REG(hw, E1000_IMC, ~0);
        E1000_WRITE_FLUSH(hw);
    }
    if (likely(netif_rx_schedule_prep(netdev))) {
        adapter->total_tx_bytes = 0;
        adapter->total_tx_packets = 0;
        adapter->total_rx_bytes = 0;
        adapter->total_rx_packets = 0;
        __netif_rx_schedule(netdev);
    } else {
        atomic_dec(&adapter->irq_sem);
    }
#else

e1000驱动的poll函数e1000_clean:
e1000_clean:
    if ((tx_clean_complete && (work_done == 0)) ||
       !netif_running(poll_dev)) {
quit_polling:
        if (likely(adapter->itr_setting & 3))
            e1000_set_itr(adapter);
        netif_rx_complete(poll_dev);
        if (test_bit(__E1000_DOWN, &adapter->state))
            atomic_dec(&adapter->irq_sem);
        else
            e1000_irq_enable(adapter);
        return 0;
    }


分析e1000的interrupt auto-mask只有在NAPI的时候开启(82571之后的芯片才支持)。
NAPI下auto-mask流程:
1.将CTRL_EXT.IAME置为1,启动Auto-Mask功能。
2.设置IAM寄存器值为0xffffffff。
3.接受到数据包,发生中断后,会设置ICR.INT_ASSERTED位。
4.如果ICR.INT_ASSERTED位为1,将IAM寄存器的值赋给IMC寄存器。在这里,就是将0xffffffff赋给IMC寄存器,也就是起到了关中断的作用。
5.在NAPI的poll函数末尾,需要开中断,调用e1000_irq_enable,设置IMS寄存器。

注意:
这种寄存器一读取就清空的策略,对于软件设计人员来将感觉很不适应。
通过使用"set"和"clear-on-read"方式,而不是"read-modify-write",来进行线程安全("thread-safe")的访问。

==========
另外还有两个中断相关的寄存器:
Interrupt Throttling Rate
ITR (000C4h; R/W)
中断上限速率寄存器:
最小内部中断间隔,间隔是以256ns进行步进的。设为0将禁止中断上限速率逻辑。

中断速率与间隔值之间的公式:
interrupts/second = (256×10^(-9) × interval)^(-1)

同理,我们也可以得出间隔值与中断速率之间的公式:
inter-interrupt interval = (256×10^(–9) × interrupts/sec)^(-1)

例如,中断间隔被设置为500d,那么以太网控制器能够保证CPU在128us内不会再被网卡中断;最大中断速率不超过7813interrupts/secon。
这个寄存器的设定由各个系统而定,推荐设定范围为651-5580 (28Bh - 15CCh).


Interrupt Cause Set Register
ICS (000C8h; W)
中断设置寄存器
软件可以设置这个寄存器来引起相应的中断。这个寄存器上设置相应的位为1,就触发相应的中断。结果就是在ICR寄存器中相应的位也被设置了(相应的中断发生了)。如果IMS寄存器允许,将会产生一个PCIe*中断。
写0不产生任何变化。
阅读(2672) | 评论(4) | 转发(0) |
给主人留下些什么吧!~~

CUDev2008-11-21 10:33:30

新的e1000代码没有怎么看,维护之前的驱动可以使PCI、PCIE接口的卡都能够使用。

CUDev2008-11-21 10:33:30

新的e1000代码没有怎么看,维护之前的驱动可以使PCI、PCIE接口的卡都能够使用。

chinaunix网友2008-11-18 20:41:31

谢谢,正是我需要的,但在新的E1000 8.06代码(只对于<82571 chipset)中,仍然没有使用 E1000_WRITE_REG(hw, E1000_IMC, ~0); E1000_WRITE_FLUSH(hw); 为何?这样不是对于象8254X的NIC有问题了吗?

chinaunix网友2008-11-18 20:41:31

谢谢,正是我需要的,但在新的E1000 8.06代码(只对于<82571 chipset)中,仍然没有使用 E1000_WRITE_REG(hw, E1000_IMC, ~0); E1000_WRITE_FLUSH(hw); 为何?这样不是对于象8254X的NIC有问题了吗?