上次说到的cs8900_start函数中,完成了中断申请任务。什么是中断?中断是一种电信号,由硬件设备产生,并直接送入中断控制器的输入引脚上,然后再由中断控制器向处理器发送相应的信号。
其中中断处理函数cs8900_interrupt没有讲。中断处理函数是中断发生时系统要执行的函数。本文将主要介绍中断处理函数的功能。我们不分析中断实现机制,而是关心中断发生时,要做哪些事情。要知道,中断处理函数设计的好坏,会直接关心到性能乃至稳定问题。
虽然我不会讲中断的实现,但是你必须清楚中断的两种类型:
1. 轮询(polling) 让内核定期对设备的状态进行查询,然后做出相应的处理;
2. 中断(interrupt) 让硬件在需要的时候向内核发出信号(变内核主动为硬件主动)。
如果你对中断的实现感兴趣,你应该去了解hw_interrupt_type、irq_desc_t 和 irqaction这些数据结构。
我们的中断处理函数通过switch/case语句判断中断类型,并进行相应处理。具体过程是:首先读出ISQ寄存器的值,然后根据ISQ的值分别处理各种情况。当中断发生时,这些中断实际反映在相应的寄存器中,ISQ寄存器用低6位记录了当前寄存器的编号,高10位记录了当前寄存器的实际内容。代码如下:
while ((status = cs8900_read (dev, PP_ISQ))) {
handled = 1;
switch (RegNum (status)) {
case RxEvent: //接收到了数据包
cs8900_receive (dev);
break;
case TxEvent: //根据open中的设置,分别处理各种类型的发送事件。
priv->stats.collisions += ColCount (cs8900_read (dev,PP_TxCOL));
if (!(RegContent (status) & TxOK)) {
priv->stats.tx_errors++;
if ((RegContent (status) & Out_of_window)) priv->stats.tx_window_errors++;
if ((RegContent (status) & Jabber)) priv->stats.tx_aborted_errors++;
break;
} else if (priv->txlen) {
priv->stats.tx_packets++;
priv->stats.tx_bytes += priv->txlen;
}
priv->txlen = 0;
netif_wake_queue (dev);
break;
case BufEvent: //两种情况,分别进行处理。
//当RxMiss置位,表示传输过程中丢帧,于是读寄存器获取丢失的包的数目。
if ((RegContent (status) & RxMiss)) {
u16 missed = MissCount (cs8900_read (dev,PP_RxMISS));
priv->stats.rx_errors += missed;
priv->stats.rx_missed_errors += missed;
}
//当TxUnderrun置位,表示在帧结束前网卡运行已过时。改变网络状态结构体中对应元素的值,接着通知上层可往下发送包数据。
if ((RegContent (status) & TxUnderrun)) {
priv->stats.tx_errors++;
priv->stats.tx_fifo_errors++;
priv->txlen = 0;
netif_wake_queue (dev);
}
/* FIXME: if Rdy4Tx, transmit last sent packet (if any) */
break;
case TxCOL: //当传输出现冲突错误时,通过读寄存器值得到当前冲突的个数,加到统计结构体中的对应元素值上。
priv->stats.collisions += ColCount (cs8900_read (dev,PP_TxCOL));
break;
case RxMISS: //读寄存器获取丢失帧的个数。
status = MissCount (cs8900_read (dev,PP_RxMISS));
priv->stats.rx_errors += status;
priv->stats.rx_missed_errors += status;
break;
}
其中的细节我们下次再说。
一句话总结:中断处理函数是中断产生时执行的函数,它根据中断种类进行处理。