函数: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(); }