linux网络设备驱动DM9000驱动分析(3)

原创 2015年07月06日 19:32:39

 转载请注明出处:http://blog.csdn.net/gotowu/article/details/46329809

10、DM9000驱动中有两个中断函数,dm9000_interruptdm9000_wol_interrupt

1dm9000_interrupt:触发中断的时机发生在:

1DM9000接收到一个包以后。

2DM9000发送完了一个包以后

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寄存器NSRNetwork 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接收控制寄存器
}



版权声明:本文为博主原创文章,转载请注明出处!

linux网络设备驱动DM9000驱动分析(4)

转载请注明出处:http://blog.csdn.net/gotowu/article/details/46329809 14、接受数据 在中断函数中,我们可以看到调用了dm9000_rx。接收数据...
  • gotowu
  • gotowu
  • 2015年07月06日 19:58
  • 499

linux 网络设备驱动-DM9000

1、Linux网络设备驱动的体系结构Linux网络驱动程序的体系结构可划分为4个层次。Linux内核源代码中提供了网络设备接口及以上层次的代码,因此移植特定网络硬件的驱动程序的主要工作就是完成设备驱动...

网络设备驱动 和 DM9000 驱动程序分析

分析内核版本:Linux 2.6.36.2。 分析网卡:DM9000 一、网络设备驱动程序分析。 1、Linux 网络设备驱动程序 分层: Linux 网络设备驱动程序从上到下可分为4层,依次为...
  • ACanoe
  • ACanoe
  • 2012年05月02日 18:41
  • 1898

Linux设备驱动工程师之路——DM9000网卡驱动程序分析(1)

DM9000是开发板经采用的网络芯片,是一种高度集成而且功耗很低的高速网络控制器,可以和CPU直连,支持10/100M以太网连接,芯片内部自带16K SARM(3KB用来发送,13KB用来接收). ...

Linux设备驱动工程师之路——DM9000网卡驱动程序分析

Linux设备驱动工程师之路——DM9000网卡驱动程序分析 K-Style   原文链接:http://blog.csdn.net/ayangke/article/details/683082...

Linux设备驱动工程师之路——DM9000网卡驱动程序分析

Linux设备驱动工程师之路——DM9000网卡驱动程序分析 K-Style 转载请注明来自于衡阳师范学院08电2  K-Style  http://blog.csdn.net/ayangke,Q...
  • ayangke
  • ayangke
  • 2011年09月28日 16:52
  • 2431

Linux网络设备驱动

  • 2012年11月22日 12:27
  • 122KB
  • 下载

Linux网络设备驱动编程

  • 2010年06月15日 15:33
  • 8KB
  • 下载

LDD3读书笔记(第13章 网络设备驱动)

这个小节给出了本章介绍过的概念的快速参考,同时解释了驱动程序应该包含的每个头文件。但是net_device和sk_buff结构的成员不会在这里重复。 #include     这个头文件保存有n...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux网络设备驱动DM9000驱动分析(3)
举报原因:
原因补充:

(最多只允许输入30个字)