我们这里描述的是硬件中断。
设备和内核之间的交互有两种方法。
1 polling(轮询)
也就是kernel来操作交互,由kernel来检测某一个状态,看是否需要让设备做什么。
2 interrupt(中断)
设备来发起交互,设备发出一个硬件中断请求给kernel当他需要kernel的注意时。
当中断来的时候被调用的函数称为interrupt handler,他必须通过设备的驱动来安装。当一个设备驱动注册一个NIC(Network Interface Card),他请求并标记了一个IRQ,然后他为这个中断请求注册一个回调函数.
其中注册回调函数与remove回调函数用下面的两个方法。
irq也就是中断请求号,handler就是中断抵达时的回调函数。irqflags是中断的类型,比如IRQF_SHARED(中断共享)等。dev_id也就是设备注册时的id。
NIC的中断的发生一般有下面的几种类型。
1 互联网帧的到达,也就是NIC接到数据。
2 传输失败。体现在用户层就是超时,等等。。
3 DMA传输成功完成。
比如有数据,通过DMA传递给NIC,由于DMA是异步的,因此设备驱动必须等待从NIC的一个显式的中断。
4 设备有足够的内存处理一个新的传输。
当egress queue没有足够的空间,也就是无法放入一帧时,NIC的驱动会关闭掉传输,并要求NIC当有比给定的内存更大的内存时发出一个中断,然后当中断来的时候会重新打开传输。
这里看一个例子:
3c509.c中的hard_start_xmit方法
这里只摘要了主要的代码,第一行停止了设备的传输队列,然后监测是否设备有足够的空间存放一帧(1536字节).如果有的话打开传输队列,否则指示设备当有足够空间的时候产生一个中断(使用outw来操作寄存器).当中断来的时候会调用netif_start_queue.
共享中断
共享中断也就是一个中断请求号关联了多个中断处理函数,当没一个设备注册中断请求号时候传递的参数声明是否这个中断能被共享。
接下来看下中断的数据结构:
irq_desc 代表中断的描述符(他是全局的)而且是与平台相关的,因此我们可以看到不同的平台实现了自己的中断处理的相关函数,而中断的处理函数是包含在action中的,其中如果action多于一个元素,就代表这个irq是共享irq。
下面的图很好的显示了irq_desc的结构。
[img]/upload/attachment/91169/151d5bab-f3ef-391d-b452-62879850b54b.jpg[/img]
设备和内核之间的交互有两种方法。
1 polling(轮询)
也就是kernel来操作交互,由kernel来检测某一个状态,看是否需要让设备做什么。
2 interrupt(中断)
设备来发起交互,设备发出一个硬件中断请求给kernel当他需要kernel的注意时。
当中断来的时候被调用的函数称为interrupt handler,他必须通过设备的驱动来安装。当一个设备驱动注册一个NIC(Network Interface Card),他请求并标记了一个IRQ,然后他为这个中断请求注册一个回调函数.
其中注册回调函数与remove回调函数用下面的两个方法。
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long irqflags, const char * devname, void *dev_id)
void free_irq(unsigned int irq, void *dev_id)
irq也就是中断请求号,handler就是中断抵达时的回调函数。irqflags是中断的类型,比如IRQF_SHARED(中断共享)等。dev_id也就是设备注册时的id。
NIC的中断的发生一般有下面的几种类型。
1 互联网帧的到达,也就是NIC接到数据。
2 传输失败。体现在用户层就是超时,等等。。
3 DMA传输成功完成。
比如有数据,通过DMA传递给NIC,由于DMA是异步的,因此设备驱动必须等待从NIC的一个显式的中断。
4 设备有足够的内存处理一个新的传输。
当egress queue没有足够的空间,也就是无法放入一帧时,NIC的驱动会关闭掉传输,并要求NIC当有比给定的内存更大的内存时发出一个中断,然后当中断来的时候会重新打开传输。
这里看一个例子:
3c509.c中的hard_start_xmit方法
netif_stop_queue (dev);
.................
if (inw(ioaddr + TX_FREE) > 1536)
netif_start_queue(dev);
else
/* Interrupt us when the FIFO has room for max-sized packet. */
outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
这里只摘要了主要的代码,第一行停止了设备的传输队列,然后监测是否设备有足够的空间存放一帧(1536字节).如果有的话打开传输队列,否则指示设备当有足够空间的时候产生一个中断(使用outw来操作寄存器).当中断来的时候会调用netif_start_queue.
共享中断
共享中断也就是一个中断请求号关联了多个中断处理函数,当没一个设备注册中断请求号时候传递的参数声明是否这个中断能被共享。
接下来看下中断的数据结构:
struct irq_desc {
irq_flow_handler_t handle_irq;
struct irq_chip *chip;
struct msi_desc *msi_desc;
void *handler_data;
void *chip_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
unsigned long last_unhandled; /* Aging timer for unhandled count */
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
const char *name;
}
irq_desc 代表中断的描述符(他是全局的)而且是与平台相关的,因此我们可以看到不同的平台实现了自己的中断处理的相关函数,而中断的处理函数是包含在action中的,其中如果action多于一个元素,就代表这个irq是共享irq。
struct irqaction {
irq_handler_t handler; ///中断处理函数
unsigned long flags;
cpumask_t mask;
const char *name;
void *dev_id;
struct irqaction *next; ///链表的指针
int irq; ///中断号
struct proc_dir_entry *dir;
};
下面的图很好的显示了irq_desc的结构。
[img]/upload/attachment/91169/151d5bab-f3ef-391d-b452-62879850b54b.jpg[/img]