• 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();
    }
  • 相关阅读:
    MySQL(六)锁机制
    MySQL(七)性能优化
    Jenkins+SVN+Maven+shell 自动化部署实践
    vue中使用echarts图表自适应窗口的几种方案
    想加入或者创建一个技术交流群。偏向前端,各位大佬有推荐吗?
    Goland 2019下载和安装(带破解补丁和汉化包)
    Elementui 表单验证 点击保存定位到验证失败处
    Scheduled 参数配置
    SpringBoot @Scheduled定时任务
    centos 7 安装 SVN服务
  • 原文地址:https://www.cnblogs.com/dream397/p/16121270.html
Copyright © 2020-2023  润新知