轉載請注明出處:http://blog.csdn.net/gotowu/article/details/46329809
10、DM9000驅動中有兩個中斷函數,dm9000_interrupt和dm9000_wol_interrupt
(1)dm9000_interrupt:觸發中斷的時機發生在:
1)DM9000接收到一個包以後。
2)DM9000發送完了一個包以後
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
int int_status;
unsigned long flags;
u8 reg_save;
dm9000_dbg(db, 3, "entering %s\n", __func__);
/* A real interrupt coming */
/* holders of db->lock must always block IRQs */
//擷取自旋鎖,關中斷
spin_lock_irqsave(&db->lock, flags);
/* Save previous register address */
reg_save = readb(db->io_addr);
/* Disable all interrupts */
iow(db, DM9000_IMR, IMR_PAR);
/* Got DM9000 interrupt status */
int_status = ior(db, DM9000_ISR); /* Got ISR */
iow(db, DM9000_ISR, int_status); /* Clear ISR status */
if (netif_msg_intr(db))
dev_dbg(db->dev, "interrupt status %02x\n", int_status);
/* Received the coming packet */
//如果是接收中斷,讀取接收的資料并存入skbuff,并送出協定上一層
if (int_status & ISR_PRS) //PRS: packet receive latch
dm9000_rx(dev);
/* Trnasmit Interrupt check */
//由于發送完了資料而觸發的發送中斷,如果還有包未發完,繼續發送。
if (int_status & ISR_PTS)
dm9000_tx_done(dev, db);
//如果是DM9000E系列的晶片,作特别處理
if (db->type != TYPE_DM9000E) {
if (int_status & ISR_LNKCHNG) {
/* fire a link-change request */
schedule_delayed_work(&db->phy_poll, 1);
}
}
/* Re-enable interrupt mask */
iow(db, DM9000_IMR, db->imr_all);
/* Restore previous register address */
writeb(reg_save, db->io_addr);
spin_unlock_irqrestore(&db->lock, flags);
return IRQ_HANDLED;
}
(2)dm9000_wol_interrupt : 這個中斷函數主要做的事情是讀dm9000寄存器NSR,WCR,根據讀到的内容作出相應提示.
static irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
board_info_t *db = netdev_priv(dev);
unsigned long flags;
unsigned nsr, wcr;
//關中斷,獲得自旋鎖
spin_lock_irqsave(&db->lock, flags);
nsr = ior(db, DM9000_NSR);
wcr = ior(db, DM9000_WCR); //WCR :wake up control register
dev_dbg(db->dev, "%s: NSR=0x%02x, WCR=0x%02x\n", __func__, nsr, wcr);
if (nsr & NSR_WAKEST) { //WAKEST :wakeup event status
/* clear, so we can avoid */
iow(db, DM9000_NSR, NSR_WAKEST);
if (wcr & WCR_LINKST)
dev_info(db->dev, "wake by link status change\n");
if (wcr & WCR_SAMPLEST)
dev_info(db->dev, "wake by sample packet\n");
if (wcr & WCR_MAGICST )
dev_info(db->dev, "wake by magic packet\n");
if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST)))
dev_err(db->dev, "wake signalled with no reason? "
"NSR=0x%02x, WSR=0x%02x\n", nsr, wcr);
}
//釋放自旋鎖,恢複本地中斷
spin_unlock_irqrestore(&db->lock, flags);
return (nsr & NSR_WAKEST) ? IRQ_HANDLED : IRQ_NONE;
}
11、在中斷中,如果還有包未發完,則會調用dm9000_tx_done。
該函數首先讀取dm9000寄存器NSR(Network Status Register)擷取發送的狀态,存在變量tx_status中,如果發送狀态為NSR_TX2END(第2個包發送完畢)或者NSR_TX1END(第1個包發送完畢),則将待發送的資料包數量(db->tx_pkt_cnt)減1,已發送的資料包數量(dev->stats.tx_packets)加1。
static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
int tx_status = ior(db, DM9000_NSR); /* NSR: 網絡狀态寄存器,讀取dm9000寄存器*/
if (tx_status & (NSR_TX2END | NSR_TX1END)) {
/* One packet sent complete */
db->tx_pkt_cnt--;
dev->stats.tx_packets++;
if (netif_msg_tx_done(db))
dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
/* Queue packet check & send */
if (db->tx_pkt_cnt > 0) //db->tx_pkt_cnt(待發送的資料包)
dm9000_send_packet(dev, db->queue_ip_summed,
db->queue_pkt_len);
netif_wake_queue(dev); //通知核心可以将待發送的資料包進入發送隊列
}
}
11、逾時函數 dm9000_timeout
發送資料失敗時,系統會調用dm9000_timeout函數。當傳輸資料逾時時,意味發送操作失敗或硬體進入未知狀态。在逾時函數中會調用netif_wake_queue()函數來重新啟動裝置發送隊列。主要的功能是儲存寄存器位址,停止隊列,重新開機并初始化DM9000,喚醒隊列,恢複寄存器位址。
static void dm9000_timeout(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
u8 reg_save;
unsigned long flags;
/* Save previous register address */
spin_lock_irqsave(&db->lock, flags);
reg_save = readb(db->io_addr); //儲存寄存器位址
netif_stop_queue(dev); //停止隊列
dm9000_reset(db); //複位
dm9000_init_dm9000(dev); //初始化
/* We can accept TX packets again */
dev->trans_start = jiffies; /* prevent tx timeout 記錄最後的資料包開始發送的時間戳*/
netif_wake_queue(dev); //重新開機發送隊列
/* Restore previous register address */
writeb(reg_save, db->io_addr); //恢複寄存器位址
spin_unlock_irqrestore(&db->lock, flags);
}
13、設定多點傳播位址dm9000_hash_table。
static void dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&db->lock, flags); //設定自旋鎖,同時儲存中斷設定
dm9000_hash_table_unlocked(dev); //調用dm9000_hash_table_unlocked來進行設定
spin_unlock_irqrestore(&db->lock, flags);//解鎖
}
dm9000_hash_table_unlocked:
static void dm9000_hash_table_unlocked(struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
struct netdev_hw_addr *ha;
int i, oft;
u32 hash_val;
u16 hash_table[4];
u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; //RCR :接收控制寄存器
//DIS_LONG:discard long packet,超出1522位元組. DIS_CRC:discard crc error packet. RXEN:RX enable
dm9000_dbg(db, 1, "entering %s\n", __func__);
for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) //PAR:實體位址寄存器
iow(db, oft, dev->dev_addr[i]); //将實體位址寫入PAR寄存器 PAB 0-5
/* Clear Hash Table */
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
/* broadcast address */
hash_table[3] = 0x8000;
//IFF : interface flags
if (dev->flags & IFF_PROMISC) // IFF_PROMISC: receive all packets
rcr |= RCR_PRMSC; //PRMSC : promiscuous mode 混雜模式
if (dev->flags & IFF_ALLMULTI) // IFF_ALLMULTI : receive all multicast packets
rcr |= RCR_ALL; //ALL : pass all multicast
/* the multicast address in Hash Table : 64 bits */
netdev_for_each_mc_addr(ha, dev) { //周遊連結清單
hash_val = ether_crc_le(6, ha->addr) & 0x3f;
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
}
/* Write the hash table to MAC MD table */
for (i = 0, oft = DM9000_MAR; i < 4; i++) { //給MAR寄存器寫值 MAR : multicast address register
iow(db, oft++, hash_table[i]);
iow(db, oft++, hash_table[i] >> 8);
}
iow(db, DM9000_RCR, rcr); //設定RCR接收控制寄存器
}