上次说到的cs8900_start函数中,完成了中断申请任务。什么是中断?中断是一种电信号,由硬件设备产生,并直接送入中断控制器的输入引脚上,然后再由中断控制器向处理器发送相应的信号。
其中中断处理函数cs8900_interrupt没有讲。中断处理函数是中断发生时系统要执行的函数。本文将主要介绍中断处理函数的功能。我们不分析中断实现机制,而是关心中断发生时,要做哪些事情。要知道,中断处理函数设计的好坏,会直接关心到性能乃至稳定问题。
虽然我不会讲中断的实现,但是你必须清楚中断的两种类型:
1. 轮询(polling)让内核定期对设备的状态进行查询,然后做出相应的处理;
2. 中断(interrupt)让硬件在需要的时候向内核发出信号(变内核主动为硬件主动)。
我们的中断处理函数通过switch/case语句判断中断类型,并进行相应处理。具体过程是:首先读出ISQ寄存器的值,然后根据ISQ的值分别处理各种情况。当中断发生时,这些中断实际反映在相应的寄存器中,ISQ寄存器用低6位记录了当前寄存器的编号,高10位记录了当前寄存器的实际内容。代码如下:
/*网卡的接收数据主要由中断引发设备的中断处理函数*/
static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
struct net_local *lp;
int ioaddr, status;
ioaddr = dev->base_addr;
//还在lp
lp = (struct net_local *)dev->priv;
/* we MUST read all the events out of the ISQ, otherwise we'll never
get interrupted again. As a consequence, we can't have any limit
on the number of times we loop in the interrupt handler. The
hardware guarantees that eventually we'll run out of events. Of
course, if you're on a slow machine, and packets are arriving
faster than you can read them off, you're screwed. Hasta la
vista, baby! */
//读取中断寄存器中的状态。
while ((status = readword(dev, ISQ_PORT))) {
DPRINTK(4, "%s: event=%04x\n", dev->name, status);
switch(status & ISQ_EVENT_MASK) {
case ISQ_RECEIVER_EVENT:
/* Got a packet(s). */
//读取数据包,所以这个case的作用是用来接收的。
//这个函数的主要作用是将sk_buffer传递给上层协议。
net_rx(dev);
break;
case ISQ_TRANSMITTER_EVENT:
lp->stats.tx_packets++;
//唤醒队列。
netif_wake_queue(dev); /* Inform upper layers. */
if ((status & ( TX_OK |
TX_LOST_CRS | TX_SQE_ERROR |
TX_LATE_COL | TX_16_COL)) != TX_OK) {
if ((status & TX_OK) == 0) lp->stats.tx_errors++;
if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
}
break;
case ISQ_BUFFER_EVENT:
if (status & READY_FOR_TX) {
/* we tried to transmit a packet earlier,
but inexplicably ran out of buffers.
That shouldn't happen since we only ever
load one packet. Shrug. Do the right
thing anyway. */
netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & TX_UNDERRUN) {
DPRINTK(1, "%s: transmit underrun\n", dev->name);
lp->send_underrun++;
if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
/* transmit cycle is done, although
frame wasn't transmitted - this
avoids having to wait for the upper
layers to timeout on us, in the
event of a tx underrun */
netif_wake_queue(dev); /* Inform upper layers. */
}
break;
case ISQ_RX_MISS_EVENT:
//继续打问号???
lp->stats.rx_missed_errors += (status >>6);
break;
case ISQ_TX_COL_EVENT:
lp->stats.collisions += (status >>6);
break;
}
}
}
在这个终端函数中数据包接收的那一部分是清楚了,但是其他的部分不是特别懂。
同时还要说一下自己的一个巨大的误区:网络接收数据的主要方法就是由中断引发设备的中断处理函数!!!
大神一句话总结:中断处理函数是中断产生时执行的函数,它根据中断种类进行处理。