e1000e驱动的MSI中断测试

网卡驱动 专栏收录该内容
14 篇文章 0 订阅

本文主要讲述一下e1000e网卡驱动的MSI中断测试,以及对通过PROC文件(/proc/irq/目录)设置的中断参数所造成的影响。

intel网卡e1000e驱动的open函数e1000_open,会测试MSI中断。所以每次在使能网卡时,都会进行中断测试。intel的其它网卡如e1000等驱动没有此项测试功能。由代码中的注释可知,是由于PCIe的一些问题导致芯片忽略掉e1000e的MSI消息,才必须进行的测试。

static int e1000_open(struct net_device *netdev)
{
    /* Work around PCIe errata with MSI interrupts causing some chipsets to
     * ignore e1000e MSI messages, which means we need to test our MSI
     * interrupt now
     */
    if (adapter->int_mode != E1000E_INT_MODE_LEGACY) {
        err = e1000_test_msi(adapter);
    }
}

核心测试函数为e1000_test_msi_interrupt。首先清除原有申请的中断(e1000_free_irq),并且重置MSI中断设置,其次重新申请一个专门用于测试的中断(pci_enable_msi),并且注册一个测试用中断处理函数(e1000_intr_msi_test);最后在测试完成之后,申请一个正常工作所用中断(e1000_request_irq)。

static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
{
    struct net_device *netdev = adapter->netdev;
    struct e1000_hw *hw = &adapter->hw;

    e1000_free_irq(adapter);
    e1000e_reset_interrupt_capability(adapter);

	adapter->flags |= FLAG_MSI_TEST_FAILED;
    err = pci_enable_msi(adapter->pdev);
    err = request_irq(adapter->pdev->irq, e1000_intr_msi_test, 0, netdev->name, netdev);

    /* fire an unusual interrupt on the test handler */
    ew32(ICS, E1000_ICS_RXSEQ);
    e1e_flush();
    msleep(100);

    if (adapter->flags & FLAG_MSI_TEST_FAILED) {
        adapter->int_mode = E1000E_INT_MODE_LEGACY;
        e_info("MSI interrupt test failed, using legacy interrupt.\n");
    } else {
        e_dbg("MSI interrupt test succeeded!\n");
    }
	
    e1000e_set_interrupt_capability(adapter);
    return e1000_request_irq(adapter);
}

MSI中断测试用的标志为FLAG_MSI_TEST_FAILED。在测试开始前置位FLAG_MSI_TEST_FAILED,紧接着主动出发一个E1000_ICR_RXSEQ的接收序列错误的中断,等待100毫秒之后,判断FLAG_MSI_TEST_FAILED标志是否清除。其标志在MSI测试中断处理函数e1000_intr_msi_test中清除,所以在正常触发了中断处理函数后,此标志就会被清除。

static irqreturn_t e1000_intr_msi_test(int __always_unused irq, void *data)
{
    u32 icr = er32(ICR);

    if (icr & E1000_ICR_RXSEQ) {
        adapter->flags &= ~FLAG_MSI_TEST_FAILED;
        wmb();
    }
}

接下来看一下在此过程中,PROC文件中的中断配置发生的变化。首先在中断关闭过程中,e1000_free_irq函数最终调用到__free_irq函数,其将删除PROC文件中的中断配置目录,例如中断号为36,其proc文件目录/proc/irq/36/将被删除,中断36相关的配置将全部消失,如中断的CPU核亲和性配置smp_affinity等将消失。

static void e1000_free_irq(struct e1000_adapter *adapter)
{
    struct net_device *netdev = adapter->netdev;

    free_irq(adapter->pdev->irq, netdev);
}
static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{
    unregister_handler_proc(irq, action);
}

另外中断重置函数e1000e_reset_interrupt_capability,将会释放MSI中断号,关闭MSI中断功能,恢复原传统的中断线的中断号,default_irq变量中保存着MSI开启之前的中断号。

void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
{
    if (adapter->flags & FLAG_MSI_ENABLED) {
        pci_disable_msi(adapter->pdev);
        adapter->flags &= ~FLAG_MSI_ENABLED;
    }
}
void pci_disable_msi(struct pci_dev *dev)
{
    pci_msi_shutdown(dev);
    free_msi_irqs(dev);
}
void pci_msi_shutdown(struct pci_dev *dev)
{
    struct msi_desc *desc;

	desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
    dev->irq = desc->msi_attrib.default_irq;
} 

重新注册中断处理函数request_irq将会创建全新的中断proc文件,具体为/proc/irq/目录下创建以中断号为名称的新目录,例如中断号为36,新目录为/proc/irq/36/。

int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, ...)
{
    struct irqaction *action;

    retval = __setup_irq(irq, desc, action);
}
static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
    register_irq_proc(irq, desc);
    register_handler_proc(irq, new);
}

通过在__setup_irq函数中调用register_irq_proc函数实现。此时创建的中断配置将是系统默认的配置参数。例如smp_affinity参数,默认使用全局变量irq_default_affinity,其在系统初始化时被设置为所有可用的CPU核。

void register_irq_proc(unsigned int irq, struct irq_desc *desc)
{
    sprintf(name, "%d", irq);

    /* create /proc/irq/1234 */
    desc->dir = proc_mkdir(name, root_irq_dir);

    /* create /proc/irq/<irq>/smp_affinity */
    proc_create_data("smp_affinity", 0600, desc->dir, &irq_affinity_proc_fops, (void *)(long)irq);
}
static void __init init_irq_default_affinity(void)
{
    alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
    cpumask_setall(irq_default_affinity);
}

至此结论是,对于e1000e驱动的网卡,由于MSI中断测试的存在,如果通过PROC文件改变了中断的smp_affinity参数,在关闭/重新使能(ifconfig eth0 down/up)网络接口操作后,smp_affinity的配置将丢失。


内核版本:Linux-4.15

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值