e1000_irq_enable pk enable_irq


函数:enable_irq( ):

函数enable_irq( )在实现过程中调用了函数__enable_irq( ),根据中断所处的深度和状态的不同,会有不同的执行结果,一般用于改变中断的状态,使中断处于唤醒状态,触发中断处理函数的执行及减少中断所处的深度,即改变字段depth的值。

static int __init enable_disable_irq_init(void)
{
    int result=0;
    printk("into enable_disable_irq_init\n");
    /*申请一个新的中断,中断号对应的是11,中断处理函数是myhandler( ),中断类型是IRQF_
        DISABLED,中断设备名是A_NEW_Device,设备编号是NULL(即不对应真实的设备)*/
    result=request_irq(irq, irq_handler, IRQF_DISABLED, "A_New_Device", NULL);
    disable_irq(irq); //调用disable_irq( )函数,使中断的深度增加1
    enable_irq(irq); //调用enable_irq( )函数,使中断的深度减少1,同时触发中断处理函数执行
    printk("the result of the request_irq is: %d\n", result);    //输出中断申请的结果
    printk("out enable_disable_irq_init\n");
    return 0;
}
static void e1000_netpoll(struct net_device *netdev)
{
    struct e1000_adapter *adapter = netdev_priv(netdev);

    if (disable_hardirq(adapter->pdev->irq))
        e1000_intr(adapter->pdev->irq, netdev);
    enable_irq(adapter->pdev->irq);
}

 enable_irq实际是对__enable_irq的封装,内部逻辑如下:

desc会有一个count值叫做desc->depth,理论上调用一次disable_irq,这个值会加1,相反调用enable_irq会减1。

对于enable_irq来说,这里有两种特殊情况:

一个是depth为0的情况下调用enable_irq,会通过WARN输出警报,这个状态下不应该有enable_irq被调用。

一个是depth为1的情况下调用enable_irq,这个状态下本来应该处于disable状态,需要实际的打开这个中断。这里调用的也是irq_enable这个函数
 

void enable_irq(unsigned int irq) 用于使能一个irq。
void disable_irq(unsigned int irq)则用于禁止一个irq

其使用的例程如下:
static void cp_poll_controller(struct net_device *dev)
{
    struct cp_private *cp = netdev_priv(dev);
    const int irq = cp->pdev->irq;

    disable_irq(irq);
    cp_interrupt(irq, dev);
    enable_irq(irq);
}
从本例中可以看到这个函数一般和disable_irq 配合使用。
其源码分析如下:
void enable_irq(unsigned int irq)
{
    unsigned long flags;
    #根据irq得到其对应的中断描述符
    struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
    #描述符为null,则直接退出.
    if (!desc)
        return;
    #中断描述符如果没有对应的chip,则打印error 信息,并退出
    if (WARN(!desc->irq_data.chip,
         KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
        goto out;
    #继续调用__enable_irq 使能中断
    __enable_irq(desc);
out:
    irq_put_desc_busunlock(desc, flags);
}


void __enable_irq(struct irq_desc *desc)
{
    switch (desc->depth) {
    case 0:
 err_out:
        WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n",
             irq_desc_get_irq(desc));
        break;
    #正常情况下第一个调用enable_irq的时候desc->depth 应该是1,如果是0的话,后面进行--操作的话就成负数了
    case 1: {
    #如果正处于suspend的过程中,则直接退出
        if (desc->istate & IRQS_SUSPENDED)
            goto err_out;
        这三个函数后面详细分析
        /* Prevent probing on this irq: */
        irq_settings_set_noprobe(desc);
        #通过chip来使能irq
        irq_enable(desc);
        check_irq_resend(desc);
        /* fall-through */
    }
    #从这里可以知道enable_irq 是可以嵌套的,即同一个irq 可以多次调用enable_irq
    default:
        desc->depth--;
    }
}

static inline void irq_settings_set_noprobe(struct irq_desc *desc)
{
    #只是或上一个_IRQ_NOPROBE flag
    desc->status_use_accessors |= _IRQ_NOPROBE;
}

void irq_enable(struct irq_desc *desc)
{
    irq_state_clr_disabled(desc);
    #正常情况下回调用chip来使能irq
    if (desc->irq_data.chip->irq_enable)
        desc->irq_data.chip->irq_enable(&desc->irq_data);
    else
        desc->irq_data.chip->irq_unmask(&desc->irq_data);
    irq_state_clr_masked(desc);
}

中断控制器回调函数

/* 中断控制器 */
static struct irq_chip bcm2708_irqchip = {
    .name = "GPIO",
    .irq_enable = bcm2708_gpio_irq_unmask,//使能该irq,通常是直接调用irq_unmask()
    .irq_disable = bcm2708_gpio_irq_mask,//禁止该irq,通常是直接调用irq_mask
    .irq_unmask = bcm2708_gpio_irq_unmask,//取消屏蔽该irq
    .irq_mask = bcm2708_gpio_irq_mask,//屏蔽该irq
    .irq_set_type = bcm2708_gpio_irq_set_type,//设置irq的电气触发条件
};

e1000_irq_enable

int e1000_open(struct net_device *netdev)
{
    struct e1000_adapter *adapter = netdev_priv(netdev);
    struct e1000_hw *hw = &adapter->hw;
    int err;

    /* disallow open during test */
    if (test_bit(__E1000_TESTING, &adapter->flags))
        return -EBUSY;

    netif_carrier_off(netdev);

    /* allocate transmit descriptors */
    err = e1000_setup_all_tx_resources(adapter);
    if (err)
        goto err_setup_tx;

    /* allocate receive descriptors */
    err = e1000_setup_all_rx_resources(adapter);
    if (err)
        goto err_setup_rx;

    e1000_power_up_phy(adapter);

    adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
    if ((hw->mng_cookie.status &
              E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
        e1000_update_mng_vlan(adapter);
    }

    /* before we allocate an interrupt, we must be ready to handle it.
     * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
     * as soon as we call pci_request_irq, so we have to setup our
     * clean_rx handler before we do so.
     */
    e1000_configure(adapter);

    err = e1000_request_irq(adapter);
    if (err)
        goto err_req_irq;

    /* From here on the code is the same as e1000_up() */
    clear_bit(__E1000_DOWN, &adapter->flags);

    napi_enable(&adapter->napi);

    e1000_irq_enable(adapter);

    netif_start_queue(netdev);

    /* fire a link status change interrupt to start the watchdog */
    ew32(ICS, E1000_ICS_LSC);

    return E1000_SUCCESS;

err_req_irq:
    e1000_power_down_phy(adapter);
    e1000_free_all_rx_resources(adapter);
err_setup_rx:
    e1000_free_all_tx_resources(adapter);
err_setup_tx:
    e1000_reset(adapter);

    return err;
}
/**
 * e1000_irq_enable - Enable default interrupt generation settings
 * @adapter: board private structure
 **/
static void e1000_irq_enable(struct e1000_adapter *adapter)
{
    struct e1000_hw *hw = &adapter->hw;

    ew32(IMS, IMS_ENABLE_MASK);
    E1000_WRITE_FLUSH();
}

相关