|
ARM-Linux驱动--DM9000网卡驱动分析(三)
[复制链接]
ARM-Linux驱动--DM9000网卡驱动分析(三)
硬件平台:FL2440(s3c2440)
内核版本:2.6.35
主机平台:Ubuntu11.04
内核版本:2.6.39
交叉编译器:arm-linuc-gcc4.3.2
原创作品,转载请标明出处http://blog.csdn.net/yming0221/article/details/6615027
本文接上文
ARM-Linux驱动--DM9000网卡驱动分析(一)
ARM-Linux驱动--DM9000网卡驱动分析(二)
下面开始看网卡设备的打开、关闭函数和操作函数
view plaincopy to clipboardprint?
01.static const struct net_device_ops dm9000_netdev_ops = {
02. .ndo_open = dm9000_open,/* 打开设备函数 */
03. .ndo_stop = dm9000_stop,/* 关闭设备函数 */
04. .ndo_start_xmit = dm9000_start_xmit,/* 开始发送数据 */
05. .ndo_tx_timeout = dm9000_timeout,/* 发送超时 */
06. .ndo_set_multicast_list = dm9000_hash_table,/* 设定多播列表 */
07. .ndo_do_ioctl = dm9000_ioctl,/* io操作函数 */
08. .ndo_change_mtu = eth_change_mtu,/* 改变MTU */
09. .ndo_validate_addr = eth_validate_addr,
10. .ndo_set_mac_address = eth_mac_addr,
11.#ifdef CONFIG_NET_POLL_CONTROLLER
12. .ndo_poll_controller = dm9000_poll_controller,
13.#endif
14.};
1、DM9000的打开函数
由于在函数alloc_netdev_mq()中分配net_device和网卡的私有数据是一起分配的,详见函数的实现
view plaincopy to clipboardprint?
01.struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
02. void (*setup)(struct net_device *), unsigned int queue_count)
03.{
04....................
05.alloc_size = sizeof(struct net_device);
06. if (sizeof_priv) {
07. /* ensure 32-byte alignment of private area */
08. alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
09. alloc_size += sizeof_priv;
10. }
11. /* ensure 32-byte alignment of whole construct */
12. alloc_size += NETDEV_ALIGN - 1;
13.
14. p = kzalloc(alloc_size, GFP_KERNEL);
15. if (!p) {
16. printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
17. return NULL;
18. }
19.
20. tx = kcalloc(queue_count, sizeof(struct netdev_queue), GFP_KERNEL);
21. if (!tx) {
22. printk(KERN_ERR "alloc_netdev: Unable to allocate "
23. "tx qdiscs.\n");
24. goto free_p;
25. }
26.
27.#ifdef CONFIG_RPS
28. rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
29. if (!rx) {
30. printk(KERN_ERR "alloc_netdev: Unable to allocate "
31. "rx queues.\n");
32. goto free_tx;
33. }
34...............
35.}
所以使用函数netdev_priv()函数返回的是网卡的私有数据的地址,函数的实现如下:
view plaincopy to clipboardprint?
01./**
02. * netdev_priv - access network device private data
03. * @dev: network device
04. *
05. * Get network device private data
06. */
07.static inline void *netdev_priv(const struct net_device *dev)
08.{
09. return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
10.}
这样两者会同时生存和消失。
dm9000_open()函数
view plaincopy to clipboardprint?
01./*
02. * Open the interface.
03. * The interface is opened whenever "ifconfig" actives it.
04. */
05.static int
06.dm9000_open(struct net_device *dev)
07.{
08. board_info_t *db = netdev_priv(dev);/* 返回board_info_t的地址 */
09. unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
10.
11. if (netif_msg_ifup(db))
12. dev_dbg(db->dev, "enabling %s\n", dev->name);
13.
14. /* If there is no IRQ type specified, default to something that
15. * may work, and tell the user that this is a problem */
16.
17. if (irqflags == IRQF_TRIGGER_NONE)
18. dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
19.
20. irqflags |= IRQF_SHARED;
21.
22. /* 注册中断 */
23. if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
24. return -EAGAIN;
25.
26. /* Initialize DM9000 board */
27. dm9000_reset(db);/* 复位DM9000 */
28. dm9000_init_dm9000(dev);/* 根据net_device的数据初始化DM9000 */
29.
30. /* Init driver variable */
31. db->dbug_cnt = 0;
32.
33. mii_check_media(&db->mii, netif_msg_link(db), 1);/* 检测mii接口的状态 */
34. netif_start_queue(dev);/* 用来告诉上层网络协定这个驱动程序还有空的缓冲区可用,请把下 一个封包送进来。*/
35.
36. /*在probe函数中初始化的等待队列 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
37. *初始化定时器,调用等待队列*/
38. dm9000_schedule_poll(db);
39.
40. return 0;
41.}
2、网卡关闭函数
view plaincopy to clipboardprint?
01./*
02. * Stop the interface.
03. * The interface is stopped when it is brought.
04. */
05.static int
06.dm9000_stop(struct net_device *ndev)
07.{
08. board_info_t *db = netdev_priv(ndev);/* 同上,获取网卡的私有结构信息的地址 */
09.
10. if (netif_msg_ifdown(db))
11. dev_dbg(db->dev, "shutting down %s\n", ndev->name);
12.
13. cancel_delayed_work_sync(&db->phy_poll);/* 终止phy_poll队列中被延迟的任务 */
14.
15. netif_stop_queue(ndev);/* 关闭发送队列 */
16. netif_carrier_off(ndev);/*通知该内核设备载波丢失,大部分涉及实际的物理连接的网络技术提供有一个载波状态,载波存在说明硬件存在并准备好*/
17.
18. /* free interrupt */
19. free_irq(ndev->irq, ndev);/* 释放中断 */
20.
21. dm9000_shutdown(ndev);/* 关闭DM9000网卡 */
22.
23. return 0;
24.}
下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收
函数如下:
view plaincopy to clipboardprint?
01.static void
02.dm9000_shutdown(struct net_device *dev)
03.{
04. board_info_t *db = netdev_priv(dev);/* 获取网卡私有信息的地址 */
05.
06. /* RESET device */
07. dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/
08. iow(db, DM9000_GPR, 0x01); /* Power-Down PHY ,关闭PHY*/
09. iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt ,关闭所有的中断*/
10. iow(db, DM9000_RCR, 0x00); /* Disable RX ,不再接受数据*/
11.}
3、接下来了解一下数据的发送函数dm9000_start_xmit
上图可以看出DM9000的SRAM中地址0x0000到0x0BFF是TXBuffer,从0x0C00到0x3FFF是RXBuffer,包的有效数据必须提前放到TXBuffer缓冲区,使用端口命令来选择MWCMD寄存器。最后设置TXCR寄存器的bit[0]TXREQ来自动发送包。
发送包的步骤如下:
(1)检查存储器宽度,通过读取ISR的bit[7:6]来确定位数
(2)写数据到TXSRAM
(3)写传输长度到TXPLL和TXPLH寄存器
(4)设置TXCR的bit[0]TXREQ来发送包
view plaincopy to clipboardprint?
01./*
02. * Hardware start transmission.
03. * Send a packet to media from the upper layer.
04. */
05.static int
06.dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
07.{
08. unsigned long flags;
09. board_info_t *db = netdev_priv(dev);/* 获取网卡虽有信息的存储结构信息的地址 */
10.
11. dm9000_dbg(db, 3, "%s:\n", __func__);
12.
13. if (db->tx_pkt_cnt > 1)
14. return NETDEV_TX_BUSY;
15.
16. spin_lock_irqsave(&db->lock, flags);/* 获得自旋锁 */
17.
18. /* Move data to DM9000 TX RAM */
19. /*MWCMD 即 Memory data write command with address increment Register(F8H)
20. * 根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2
21. */
22. writeb(DM9000_MWCMD, db->io_addr);
23.
24. (db->outblk)(db->io_data, skb->data, skb->len);/* 将数据从sk_buff中copy到网卡的TX SRAM中 */
25.
26. dev->stats.tx_bytes += skb->len;/* 统计发送的字节数 */
27.
28. db->tx_pkt_cnt++;/* 待发送计数 */
29. /* TX control: First packet immediately send, second packet queue */
30. if (db->tx_pkt_cnt == 1) {
31. dm9000_send_packet(dev, skb->ip_summed, skb->len);/* 如果计数为1,直接发送 */
32. } else {/* 如果是第2个,则 */
33. /* Second packet */
34. db->queue_pkt_len = skb->len;
35. db->queue_ip_summed = skb->ip_summed;
36. netif_stop_queue(dev);/* 告诉上层停止发送 */
37. }
38. spin_unlock_irqrestore(&db->lock, flags);/* 解锁 */
39. /* free this SKB ,释放SKB*/
40. dev_kfree_skb(skb);
41.
42. return NETDEV_TX_OK;
43.}
上面函数调用下面的函数 dm9000_send_packet来发送数据
view plaincopy to clipboardprint?
01.static void dm9000_send_packet(struct net_device *dev,
02. int ip_summed,
03. u16 pkt_len)
04.{
05. board_info_t *dm = to_dm9000_board(dev);
06.
07. /* The DM9000 is not smart enough to leave fragmented packets alone. */
08. if (dm->ip_summed != ip_summed) {
09. if (ip_summed == CHECKSUM_NONE)
10. iow(dm, DM9000_TCCR, 0);
11. else
12. iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
13. dm->ip_summed = ip_summed;
14. }
15.
16. /* Set TX length to DM9000 */
17. /* 设置TX数据的长度到寄存器TXPLL和TXPLH */
18. iow(dm, DM9000_TXPLL, pkt_len);
19. iow(dm, DM9000_TXPLH, pkt_len >> 8);
20.
21. /* Issue TX polling command */
22. /* 设置发送控制寄存器的发送请求位 */
23. iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
24.}
5、下面看一下当一个数据包发送完成后的中断处理函数dm9000_tx_done
view plaincopy to clipboardprint?
01./*
02. * DM9000 interrupt handler
03. * receive the packet to upper layer, free the transmitted packet
04. */
05.
06.static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
07.{
08. int tx_status = ior(db, DM9000_NSR); /* Got TX status */
09.
10. if (tx_status & (NSR_TX2END | NSR_TX1END)) {/* 第一个或第二个数据包发送完毕 */
11. /* One packet sent complete */
12. db->tx_pkt_cnt--;/* 待发送的数据包个数减1 */
13. dev->stats.tx_packets++;/* 发送的数据包加1 */
14.
15. if (netif_msg_tx_done(db))
16. dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
17.
18. /* Queue packet check & send */
19. if (db->tx_pkt_cnt > 0)/* 如果还有数据包 */
20. dm9000_send_packet(dev, db->queue_ip_summed,
21. db->queue_pkt_len);
22. netif_wake_queue(dev);/* 告诉内核,将数据包放入发生那个队列 */
23. }
24.}
|
|