首页 > 代码库 > DM9000 网卡驱动程序分析

DM9000 网卡驱动程序分析

平台:MINI2440

系统:Linux-2.6.36.2

mach-s3c2410/include/mach/map.h:

#define S3C2410_CS4 (0x20000000)  //AEN接nGCS4,BANK4

mach-mini2440.c:

#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)   //TXD[2:0]悬空
static struct resource mini2440_dm9k_resource[] = {
        [0] = {
                .start = MACH_MINI2440_DM9K_BASE,
                .end   = MACH_MINI2440_DM9K_BASE + 3,
                .flags = IORESOURCE_MEM
        },
        [1] = {
                .start = MACH_MINI2440_DM9K_BASE + 4,
                .end   = MACH_MINI2440_DM9K_BASE + 7,
                .flags = IORESOURCE_MEM
        },
        [2] = {
                .start = IRQ_EINT7,   //中断使用了EINT7.
                .end   = IRQ_EINT7,
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
        }
};
DM9000平台设备的定义:

static struct dm9000_plat_data mini2440_dm9k_pdata = http://www.mamicode.com/{>板子初始化时将平台设备驱动加载到总线上:

static struct platform_device *mini2440_devices[] __initdata = http://www.mamicode.com/{>dm9000.c:platform_driver与重要操作函数:

static struct platform_driver dm9000_driver = {
	.driver	= {
		.name    = "dm9000",
		.owner	 = THIS_MODULE,
	},
	.probe   = dm9000_probe,
	.remove  = __devexit_p(dm9000_drv_remove),
	.suspend = dm9000_drv_suspend,
	.resume  = dm9000_drv_resume,
};
net_device_ops与重要操作函数:

static const struct net_device_ops dm9000_netdev_ops = {
	.ndo_open		= dm9000_open,
	.ndo_stop		= dm9000_stop,
	.ndo_start_xmit		= dm9000_start_xmit,
	.ndo_tx_timeout		= dm9000_timeout,
	.ndo_set_multicast_list	= dm9000_hash_table,
	.ndo_do_ioctl		= dm9000_ioctl,
	.ndo_change_mtu		= eth_change_mtu,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address	= eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= dm9000_poll_controller,
#endif
};
ethtool_ops:

static const struct ethtool_ops dm9000_ethtool_ops = {  //查询与设置网卡的参数
	.get_drvinfo		= dm9000_get_drvinfo,
	.get_settings		= dm9000_get_settings,
	.set_settings		= dm9000_set_settings,
	.get_msglevel		= dm9000_get_msglevel,
	.set_msglevel		= dm9000_set_msglevel,
	.nway_reset		= dm9000_nway_reset,
	.get_link		= dm9000_get_link,
 	.get_eeprom_len		= dm9000_get_eeprom_len,
 	.get_eeprom		= dm9000_get_eeprom,
 	.set_eeprom		= dm9000_set_eeprom,
};
board_info结构体,内容是与芯片相关的信息:

typedef struct board_info {

	void __iomem	*io_addr;	/* Register I/O base address */
	void __iomem	*io_data;	/* Data I/O address */
	u16		 irq;		/* IRQ */
	u16		tx_pkt_cnt;
	u16		queue_pkt_len;
	u16		queue_start_addr;
	u16		dbug_cnt;
	u8		io_mode;		/* 0:word, 2:byte */
	u8		phy_addr;
	u8		imr_all;
	unsigned int	flags;
	unsigned int	in_suspend :1;
	int		debug_level;
	enum dm9000_type type;
	void (*inblk)(void __iomem *port, void *data, int length);
	void (*outblk)(void __iomem *port, void *data, int length);
	void (*dumpblk)(void __iomem *port, int length);
	struct device	*dev;	     /* parent device */
	struct resource	*addr_res;   /* resources found */
	struct resource *data_res;
	struct resource	*addr_req;   /* resources requested */
	struct resource *data_req;
	struct resource *irq_res;
	struct mutex	 addr_lock;	/* phy and eeprom access lock */
	struct delayed_work phy_poll;
	struct net_device  *ndev;
	spinlock_t	lock;
	struct mii_if_info mii;
	u32		msg_enable;
} board_info_t;
注册平台驱动:

static int __init dm9000_init(void)
{
	printk(KERN_INFO "%s Ethernet Driver, V%s/n", CARDNAME, DRV_VERSION);
	return platform_driver_register(&dm9000_driver);
}
完成match之后执行Probe函数,获得资源信息,最终注册网络设备。

dm9000_remove:在卸载时使用,释放内存空间:

static int __devexit dm9000_drv_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);

	platform_set_drvdata(pdev, NULL);

	unregister_netdev(ndev);
	dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));
	free_netdev(ndev);		/* free device structure */

	dev_dbg(&pdev->dev, "released and freed device/n");
	return 0;
}
dm9000_suspend:并没有将网络设备从内核移除,只是标志设备为removed状态,并设置挂起标志位,最后关闭设备:

static int dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db;

	if (ndev) {
		db = netdev_priv(ndev);
		db->in_suspend = 1;

		if (netif_running(ndev)) {
			netif_device_detach(ndev);
			dm9000_shutdown(ndev);
		}
	}
	return 0;
}
dm9000_resume:
static int dm9000_drv_resume(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db = netdev_priv(ndev);

	if (ndev) {

		if (netif_running(ndev)) {
			dm9000_reset(db);
			dm9000_init_dm9000(ndev);
			netif_device_attach(ndev);//标志为attach状态。
		}
		db->in_suspend = 0;
	}
	return 0;
}
dm9000_open:向内核注册中断:

static int dm9000_open(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

	if (netif_msg_ifup(db))
		dev_dbg(db->dev, "enabling %s\n", dev->name);
	/* If there is no IRQ type specified, default to something that
	 * may work, and tell the user that this is a problem */
	if (irqflags == IRQF_TRIGGER_NONE)
		dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
	irqflags |= IRQF_SHARED;
	if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))  //注册中断
		return -EAGAIN;
	/* Initialize DM9000 board */
	dm9000_reset(db);
	dm9000_init_dm9000(dev);
	/* Init driver variable */
	db->dbug_cnt = 0;
	mii_check_media(&db->mii, netif_msg_link(db), 1);
	netif_start_queue(dev);
	dm9000_schedule_poll(db);
	return 0;
}
dm9000_stop:

static int dm9000_stop(struct net_device *ndev)
{
	board_info_t *db = netdev_priv(ndev);

	if (netif_msg_ifdown(db))
		dev_dbg(db->dev, "shutting down %s\n", ndev->name);
	cancel_delayed_work_sync(&db->phy_poll);
	netif_stop_queue(ndev);
	netif_carrier_off(ndev);                  
	free_irq(ndev->irq, ndev);
	dm9000_shutdown(ndev);
	return 0;
}
dm9000_start_xmit():发送数据包函数:

static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	board_info_t *db = netdev_priv(dev);
	dm9000_dbg(db, 3, "%s:/n", __func__);
	if (db->tx_pkt_cnt > 1)
		return NETDEV_TX_BUSY;
        /*获得自旋锁*/
	spin_lock_irqsave(&db->lock, flags); 
	/* Move data to DM9000 TX RAM */
	writeb(DM9000_MWCMD, db->io_addr);
	(db->outblk)(db->io_data, skb->data, skb->len);//将skbuffer中的data写入DM9000的TX RAM,并计数
	dev->stats.tx_bytes += skb->len;
	db->tx_pkt_cnt++;
	/* TX control: First packet immediately send, second packet queue */
	if (db->tx_pkt_cnt == 1) {           //如果是第一个包
		/* Set TX length to DM9000 */
		iow(db, DM9000_TXPLL, skb->len);
		iow(db, DM9000_TXPLH, skb->len >> 8);

		/* Issue TX polling command */
		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */

		dev->trans_start = jiffies;	/* save the time stamp */
	} else {    //不是第一个包
		/* Second packet */
		db->queue_pkt_len = skb->len;
		netif_stop_queue(dev);
	}
        /*释放自旋锁*/
	spin_unlock_irqrestore(&db->lock, flags);
	/* free this SKB */
	dev_kfree_skb(skb);
	return 0;
}
dm9000_timeout():超时调用:

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 */   //保存寄存器地址
	reg_save = readb(db->io_addr);
	spin_lock_irqsave(&db->lock, flags);

	netif_stop_queue(dev);                 //停止队列
	dm9000_reset(db);
	dm9000_init_dm9000(dev);               //重启并初始化DM9000
	/* We can accept TX packets again */
	dev->trans_start = jiffies;
	netif_wake_queue(dev);                 //唤醒队列

	/* Restore previous register address */  //恢复寄存器地址
	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock, flags);
}
dm9000_hash_table():设置组播地址:

static void dm9000_hash_table(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	struct dev_mc_list *mcptr = dev->mc_list;
	int mc_cnt = dev->mc_count;
	int i, oft;
	u32 hash_val;
	u16 hash_table[4];
	u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;
	unsigned long flags;
	dm9000_dbg(db, 1, "entering %s/n", __func__);
	spin_lock_irqsave(&db->lock, flags);
	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
		iow(db, oft, dev->dev_addr[i]);
	/* Clear Hash Table */
	for (i = 0; i < 4; i++)
		hash_table[i] = 0x0;
	/* broadcast address */
	hash_table[3] = 0x8000;
	if (dev->flags & IFF_PROMISC)
		rcr |= RCR_PRMSC;

	if (dev->flags & IFF_ALLMULTI)
		rcr |= RCR_ALL;
	/* the multicast address in Hash Table : 64 bits */
	for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
		hash_val = ether_crc_le(6, mcptr->dmi_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++) {
		iow(db, oft++, hash_table[i]);
		iow(db, oft++, hash_table[i] >> 8);
	}
	iow(db, DM9000_RCR, rcr);
	spin_unlock_irqrestore(&db->lock, flags);
}
dm9000_rx():接收函数:

static void dm9000_rx(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	struct dm9000_rxhdr rxhdr;
	struct sk_buff *skb;
	u8 rxbyte, *rdptr;
	bool GoodPacket;
	int RxLen;
	/* Check packet ready or not */
	do {
		ior(db, DM9000_MRCMDX);	/* Dummy read */
		/* Get most updated data */
		rxbyte = readb(db->io_data);
		/* Status check: this byte must be 0 or 1 */
		if (rxbyte > DM9000_PKT_RDY) {
			dev_warn(db->dev, "status check fail: %d/n", rxbyte);
			iow(db, DM9000_RCR, 0x00);	/* Stop Device */
			iow(db, DM9000_ISR, IMR_PAR);	/* Stop INT request */
			return;
		}
		if (rxbyte != DM9000_PKT_RDY)
			return;
		/* A packet ready now  & Get status/length */
		GoodPacket = true;
		writeb(DM9000_MRCMD, db->io_addr);
		(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));//读四个字节到rxhdr变量
		RxLen = le16_to_cpu(rxhdr.RxLen);
		if (netif_msg_rx_status(db))
			dev_dbg(db->dev, "RX: status %02x, length %04x/n",
				rxhdr.RxStatus, RxLen);
		/* Packet Status check */
		if (RxLen < 0x40) {
			GoodPacket = false;
			if (netif_msg_rx_err(db))
				dev_dbg(db->dev, "RX: Bad Packet (runt)/n");
		}
		if (RxLen > DM9000_PKT_MAX) {
			dev_dbg(db->dev, "RST: RX Len:%x/n", RxLen);
		}
		/* rxhdr.RxStatus is identical to RSR register. */
		if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
				      RSR_PLE | RSR_RWTO |
				      RSR_LCS | RSR_RF)) {
			GoodPacket = false;
			if (rxhdr.RxStatus & RSR_FOE) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "fifo error/n");
				dev->stats.rx_fifo_errors++;
			}
			if (rxhdr.RxStatus & RSR_CE) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "crc error/n");
				dev->stats.rx_crc_errors++;
			}
			if (rxhdr.RxStatus & RSR_RF) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "length error/n");
				dev->stats.rx_length_errors++;
			}
		}
		/* Move data from DM9000 */   //将RX SRAM中的data放到sk_buffer。
		if (GoodPacket
		    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
			skb_reserve(skb, 2);
			rdptr = (u8 *) skb_put(skb, RxLen - 4);
			/* Read received packet from RX SRAM */
			(db->inblk)(db->io_data, rdptr, RxLen);
			dev->stats.rx_bytes += RxLen;
			/* Pass to upper layer */
			skb->protocol = eth_type_trans(skb, dev);
			netif_rx(skb);
			dev->stats.rx_packets++;
		} else {
			/* need to dump the packet's data */
			(db->dumpblk)(db->io_data, RxLen);
		}
	} while (rxbyte == DM9000_PKT_RDY);
}
dm9000_interrupt:

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 */
	if (int_status & ISR_PRS)
		dm9000_rx(dev);               //取数据
	/* Trnasmit Interrupt check */
	if (int_status & ISR_PTS)
		dm9000_tx_done(dev, db);      //调用done函数

	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;
}
dm9000_tx_done:

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
	int tx_status = ior(db, DM9000_NSR);	/* Got TX status */  //读取NSR的状态,得知发送的状态
	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) {
			iow(db, DM9000_TXPLL, db->queue_pkt_len);
			iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
			iow(db, DM9000_TCR, TCR_TXREQ);
			dev->trans_start = jiffies;
		}  //通知内核可以将待发送的数据包进入发送队列
		netif_wake_queue(dev);
	}
}

DM9000 网卡驱动程序分析