s3c6410自带的DM9000网卡驱动也是基于platform设备模型。
其定义的设备资源在arch/arm/mach-s3c64xx/mach-smdk6410中。有网卡的resource resource dm9000_resources[],还有一些板级信息,dm9000_plat_data dm9000_setup。
1.宏及参数 //板级、系统定义
1 #define DM9000_PHY 0x40 /* PHY address 0x01 */ 2 3 #define CARDNAME "dm9000" 4 #define DRV_VERSION "1.31" 5 /* 6 * Transmit timeout, default 5 seconds. 7 */ 8 static int watchdog = 5000; //5s的延时时间 9 module_param(watchdog, int, 0400);10 MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");11 enum dm9000_type { //开发板定义了三个DM9000类型12 TYPE_DM9000E, /* original DM9000 */13 TYPE_DM9000A,14 TYPE_DM9000B15 };
2.模块注册
此处因为基于platform模型,采用platform_driver_register函数注册内核模块,当设备驱动与设备匹配真确后,转入执行dm9000_probe()函数,该函数包含真正的dm9000网卡驱动注册函数是register_netdev()函数。
1 static int __init dm9000_init(void)2 {3 printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);4 5 return platform_driver_register(&dm9000_driver); //platform设备模型注册驱动6 }
dm9000的platform设备驱动函数如下:
1 static struct platform_driver dm9000_driver = {2 .driver = {3 .name = "dm9000",4 .owner = THIS_MODULE,5 .pm = &dm9000_drv_pm_ops,6 },7 .probe = dm9000_probe,8 .remove = __devexit_p(dm9000_drv_remove),9 };
3.dm9000_probe函数
主要完成网络设备的初始化,以及网卡驱动的注册register_netdev()
1 static int __devinit dm9000_probe(struct platform_device *pdev) 2 { 3 struct dm9000_plat_data *pdata = pdev->dev.platform_data;//驱动程序中获得系统定义的网卡板级信息 4 //定义在/arch/arm/mach-s3c64xx/mach-smdk6410.c中。 5 struct board_info *db; /* Point a board information structure */ 6 struct net_device *ndev; //定义设备结构体 7 const unsigned char *mac_src; 8 int ret = 0; 9 int iosize; 10 int i; 11 u32 id_val; 12 13 /* Init network device */ 14 //分配生成net_device结构体 alloc_etherdev是alloc_netdev()针对以太网的快捷操作函数 15 ndev = alloc_etherdev(sizeof(struct board_info)); 16 17 //判断是否分配正确 18 if (!ndev) { 19 dev_err(&pdev->dev, "could not allocate device.\n"); 20 return -ENOMEM; 21 } 22 //建立net_device到device的连接 23 SET_NETDEV_DEV(ndev, &pdev->dev); 24 //内核输出信息 25 dev_dbg(&pdev->dev, "dm9000_probe()\n"); 26 //函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。 27 /* setup board info structure */ 28 db = netdev_priv(ndev); 29 30 db->dev = &pdev->dev; 31 db->ndev = ndev; 32 33 spin_lock_init(&db->lock);//初始化自旋锁 34 mutex_init(&db->addr_lock); 35 36 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //?? 37 //获取平台设备资源 resource 地址空间、数据空间、中断信号 7号中断 38 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 39 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 40 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 41 //判断资源是否获取成功 42 if (db->addr_res == NULL || db->data_res == NULL || 43 db->irq_res == NULL) { 44 dev_err(db->dev, "insufficient resources\n"); 45 ret = -ENOENT; 46 goto out; 47 } 48 //platform_get_resource的变体 同 platform_get_resource(pdev, IORESOURCE_IRQ, 1) 49 db->irq_wake = platform_get_irq(pdev, 1); 50 if (db->irq_wake >= 0) { 51 dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake); 52 //前面获得中断号 申请中断 53 ret = request_irq(db->irq_wake, dm9000_wol_interrupt, 54 IRQF_SHARED, dev_name(db->dev), ndev); 55 if (ret) { 56 dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret); 57 } else { 58 /* test to see if irq is really wakeup capable */ 59 ret = set_irq_wake(db->irq_wake, 1); 60 if (ret) { 61 dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", 62 db->irq_wake, ret); 63 ret = 0; 64 } else { 65 set_irq_wake(db->irq_wake, 0); 66 db->wake_supported = 1; 67 } 68 } 69 } 70 //IO资源分配大小 地址 为resource分配内存 71 iosize = resource_size(db->addr_res); 72 db->addr_req = request_mem_region(db->addr_res->start, iosize, 73 pdev->name); //内存申请 74 75 if (db->addr_req == NULL) { 76 dev_err(db->dev, "cannot claim address reg area\n"); 77 ret = -EIO; 78 goto out; 79 } 80 81 db->io_addr = ioremap(db->addr_res->start, iosize); 82 83 if (db->io_addr == NULL) { 84 dev_err(db->dev, "failed to ioremap address reg\n"); 85 ret = -EINVAL; 86 goto out; 87 } 88 89 iosize = resource_size(db->data_res); 90 db->data_req = request_mem_region(db->data_res->start, iosize, 91 pdev->name); 92 93 if (db->data_req == NULL) { 94 dev_err(db->dev, "cannot claim data reg area\n"); 95 ret = -EIO; 96 goto out; 97 } 98 99 db->io_data = ioremap(db->data_res->start, iosize);100 101 if (db->io_data == NULL) {102 dev_err(db->dev, "failed to ioremap data reg\n");103 ret = -EINVAL;104 goto out;105 }106 //初始化net_device中的成员107 /* fill in parameters for net-dev structure */108 ndev->base_addr = (unsigned long)db->io_addr; //网络接口的IO基地址109 ndev->irq = db->irq_res->start;//中断号 ifconfig时会打印出这个值 也可通过这个修改110 111 /* ensure at least we have a default set of IO routines */112 dm9000_set_io(db, iosize); 113 114 /* check to see if anything is being over-ridden */115 if (pdata != NULL) {116 /* check to see if the driver wants to over-ride the117 * default IO width */118 //检测与板级信息是否相同119 if (pdata->flags & DM9000_PLATF_8BITONLY)120 dm9000_set_io(db, 1);121 122 if (pdata->flags & DM9000_PLATF_16BITONLY)123 dm9000_set_io(db, 2);124 125 if (pdata->flags & DM9000_PLATF_32BITONLY)126 dm9000_set_io(db, 4);127 128 /* check to see if there are any IO routine129 * over-rides */130 131 if (pdata->inblk != NULL)132 db->inblk = pdata->inblk;133 134 if (pdata->outblk != NULL)135 db->outblk = pdata->outblk;136 137 if (pdata->dumpblk != NULL)138 db->dumpblk = pdata->dumpblk;139 140 db->flags = pdata->flags;141 }142 143 #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL144 db->flags |= DM9000_PLATF_SIMPLE_PHY;145 #endif146 147 dm9000_reset(db);148 149 /* try multiple times, DM9000 sometimes gets the read wrong */150 for (i = 0; i < 8; i++) { //宏定义在dm9000.h中151 id_val = ior(db, DM9000_VIDL);152 id_val |= (u32)ior(db, DM9000_VIDH) << 8;153 id_val |= (u32)ior(db, DM9000_PIDL) << 16;154 id_val |= (u32)ior(db, DM9000_PIDH) << 24;155 156 if (id_val == DM9000_ID)157 break;158 dev_err(db->dev, "read wrong id 0x%08x\n", id_val);159 }160 161 if (id_val != DM9000_ID) {162 dev_err(db->dev, "wrong id: 0x%08x\n", id_val);163 ret = -ENODEV;164 goto out;165 }166 167 /* Identify what type of DM9000 we are working on */168 169 id_val = ior(db, DM9000_CHIPR);170 dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);171 172 switch (id_val) {173 case CHIPR_DM9000A:174 db->type = TYPE_DM9000A;175 break;176 case CHIPR_DM9000B:177 db->type = TYPE_DM9000B;178 break;179 default:180 dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);181 db->type = TYPE_DM9000E;182 }183 184 /* dm9000a/b are capable of hardware checksum offload */185 if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {186 db->can_csum = 1;187 db->rx_csum = 1;188 ndev->features |= NETIF_F_IP_CSUM;189 }190 191 /* from this point we assume that we have found a DM9000 */192 193 /* driver system function */ //初始化以太网设备的公有成员194 ether_setup(ndev);//在调用register_netdev之前必须初始化完全。该函数中为net_device设置了很多默认值195 196 ndev->netdev_ops = &dm9000_netdev_ops;197 ndev->watchdog_timeo = msecs_to_jiffies(watchdog);198 ndev->ethtool_ops = &dm9000_ethtool_ops;199 200 db->msg_enable = NETIF_MSG_LINK;201 db->mii.phy_id_mask = 0x1f;202 db->mii.reg_num_mask = 0x1f;203 db->mii.force_media = 0;204 db->mii.full_duplex = 0;205 db->mii.dev = ndev;206 db->mii.mdio_read = dm9000_phy_read;207 db->mii.mdio_write = dm9000_phy_write;208 209 mac_src = "eeprom";210 211 /* try reading the node address from the attached EEPROM */212 for (i = 0; i < 6; i += 2)213 dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);214 215 if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {216 mac_src = "platform data";217 memcpy(ndev->dev_addr, pdata->dev_addr, 6);218 }219 220 if (!is_valid_ether_addr(ndev->dev_addr)) {221 /* try reading from mac */222 223 mac_src = "chip";224 for (i = 0; i < 6; i++)225 ndev->dev_addr[i] = ior(db, i+DM9000_PAR);226 }227 228 if (!is_valid_ether_addr(ndev->dev_addr))229 dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "230 "set using ifconfig\n", ndev->name);231 232 platform_set_drvdata(pdev, ndev);233 ret = register_netdev(ndev); //注册net_device结构体234 235 if (ret == 0)236 printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",237 ndev->name, dm9000_type_to_char(db->type),238 db->io_addr, db->io_data, ndev->irq,239 ndev->dev_addr, mac_src);240 return 0;241 242 out:243 dev_err(db->dev, "not found (%d).\n", ret);244 245 dm9000_release_board(pdev, db);246 free_netdev(ndev); //分配错误则释放net_device结构247 248 return ret;249 }
模块加载后转入probe中执行,在probe中完成了分配net_device、网络设备的初始化,设备驱动的加载。
先是分配获得了net_device结构体等。
网络设备初始化包括:
进行硬件上的准备工作,检查网络设备是否存在,检测所使用的硬件资源。主要是resource
获得软件接口上的准备工作。
获得私有数据指针,初始化以太网设备公有成员、初始化成员,初始化自旋锁或并发同步机制、申请设备所需的硬件资源 request_region等。
在网络设备驱动程序完成模块注册时,会调用dm9000_probe()函数进行初始化,分配并初始化net_device结构体。其中有些成员在dm9000_probe()中已经完成初始化,还有一些函数指针例如(*open)()、(*release)()等函数,也是在驱动程序中进行定义。
4.dm9000_open()
open函数在执行ifconfig命令时会被激活。主要作用是打开网络设备,获得设备所需的IO地址,IRQ、DMA通道等。 注册中断、设置寄存器、启动发送队列。
在字符设备驱动中是把中断注册放在模块初始化函数中,而网卡驱动则放在open函数中。原因是网卡有禁用操作,当被禁用的时候,要把占用的中断号释放。
1 m9000_open(struct net_device *dev) 2 { 3 board_info_t *db = netdev_priv(dev);//获取设备私有数据 返回board_info_t的地址 4 unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; 5 6 if (netif_msg_ifup(db)) 7 dev_dbg(db->dev, "enabling %s\n", dev->name); 8 9 /* If there is no IRQ type specified, default to something that10 * may work, and tell the user that this is a problem */11 12 if (irqflags == IRQF_TRIGGER_NONE)13 dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");14 15 irqflags |= IRQF_SHARED;16 //注册中断17 if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))18 return -EAGAIN;19 20 /* Initialize DM9000 board */21 dm9000_reset(db); //复位DM900022 dm9000_init_dm9000(dev); //初始化dm9000中net_device结构中的成员23 24 /* Init driver variable */25 db->dbug_cnt = 0;26 27 mii_check_media(&db->mii, netif_msg_link(db), 1);//检测mii接口状态28 netif_start_queue(dev); //启动发送队列 协议栈向网卡发送29 30 dm9000_schedule_poll(db);31 32 return 0;33 }
5.stop()
设备关闭函数
tatic 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); /* 终止phy_poll队列中被延迟的任务 */ netif_stop_queue(ndev); /* 关闭发送队列 */ netif_carrier_off(ndev); /* free interrupt */ free_irq(ndev->irq, ndev); /* 释放中断 */ dm9000_shutdown(ndev); /* 关闭DM9000网卡 */ return 0;}
6.dm9000_shutdown()
下面是调用的dm9000_shutdown(ndev)函数,该函数的功能是复位phy,配置寄存器GPR位0为1,关闭dm9000电源,配置寄存器IMR位7为1,disable中断,配置寄存器RCR,disable接收.
1 static void dm9000_shutdown(struct net_device *dev) 2 { 3 board_info_t *db = netdev_priv(dev); 4 5 /* RESET device */ 6 dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/ 7 iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */ 8 iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt ,关闭所有的中断*/ 9 iow(db, DM9000_RCR, 0x00); /* Disable RX ,不再接受数据*/10 }
7.数据发送函数
数据包发送流程:
1)设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区中。
2)设置硬件寄存器,驱动网络设备进行数据发送操作。
1 static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) 2 { 3 unsigned long flags; 4 board_info_t *db = netdev_priv(dev); 5 6 dm9000_dbg(db, 3, "%s:\n", __func__); 7 8 if (db->tx_pkt_cnt > 1) 9 return NETDEV_TX_BUSY;10 11 spin_lock_irqsave(&db->lock, flags); //获得自旋锁12 13 /* Move data to DM9000 TX RAM */14 writeb(DM9000_MWCMD, db->io_addr); //根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 215 16 (db->outblk)(db->io_data, skb->data, skb->len); //将数据从sk_buff中copy到网卡的TX SRAM中17 dev->stats.tx_bytes += skb->len; //统计发送的字节数18 19 db->tx_pkt_cnt++; //待发送计数 20 /* TX control: First packet immediately send, second packet queue */21 if (db->tx_pkt_cnt == 1) { //如果计数为1,直接发送22 dm9000_send_packet(dev, skb->ip_summed, skb->len);23 } else {24 /* Second packet */25 db->queue_pkt_len = skb->len;26 db->queue_ip_summed = skb->ip_summed;27 netif_stop_queue(dev); //告诉上层停止发送28 }29 30 spin_unlock_irqrestore(&db->lock, flags);//解锁31 32 /* free this SKB */33 dev_kfree_skb(skb); //释放SKB34 35 return NETDEV_TX_OK;36 }
dm9000_start_xmit通过调用dm9000_send_packet来发送数据。
8.发送数据
dm9000_start_xmit函数中获得要发送的数据字节数,并调用dm9000_send_packet来发送数据。
1 static void dm9000_send_packet(struct net_device *dev, 2 int ip_summed, 3 u16 pkt_len) 4 { 5 board_info_t *dm = to_dm9000_board(dev); 6 7 /* The DM9000 is not smart enough to leave fragmented packets alone. */ 8 if (dm->ip_summed != ip_summed) { 9 if (ip_summed == CHECKSUM_NONE)10 iow(dm, DM9000_TCCR, 0);11 else12 iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);13 dm->ip_summed = ip_summed;14 }15 16 /* Set TX length to DM9000 *///设置发送数据的长度到TXPLL\TXPLH中17 iow(dm, DM9000_TXPLL, pkt_len);18 iow(dm, DM9000_TXPLH, pkt_len >> 8);19 20 /* Issue TX polling command *///设置发送寄存器的发送控制位,启动发送数据21 iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */22 }
9.发送超时函数
发送数据时并不一定会成功,系统会调用dm9000_timeout函数。当传输数据超时时,意味发送操作失败或硬件进入未知状态。在超时函数中会调用netif_wake_queue()函数来重新启动设备发送队列。
1 static void dm9000_timeout(struct net_device *dev) 2 { 3 board_info_t *db = netdev_priv(dev); 4 u8 reg_save; 5 unsigned long flags; 6 7 /* Save previous register address */ 8 reg_save = readb(db->io_addr); 9 spin_lock_irqsave(&db->lock, flags);10 11 netif_stop_queue(dev);12 dm9000_reset(db);13 dm9000_init_dm9000(dev);14 /* We can accept TX packets again */15 dev->trans_start = jiffies; /* prevent tx timeout */16 netif_wake_queue(dev); //重启发送队列17 18 /* Restore previous register address */19 writeb(reg_save, db->io_addr);20 spin_unlock_irqrestore(&db->lock, flags);21 }
由此, netif_wake_queue()函数与netif_stop_queue()是数据发送流程中要调用的两个重要的函数,分别用于唤醒和阻止上层向下层传送数据包。原型定义于include/linux/netdevice.h中。
10.发送中断处理函数
当一个数据包发送完成后会产生一个中断,进入中断处理函数。
1 static void dm9000_tx_done(struct net_device *dev, board_info_t *db) 2 { 3 int tx_status = ior(db, DM9000_NSR); /* Got TX status */ 4 5 if (tx_status & (NSR_TX2END | NSR_TX1END)) { //检测一个数据包发送完毕 6 /* One packet sent complete */ 7 db->tx_pkt_cnt--; //待发送的数据包数减1 8 dev->stats.tx_packets++;//已发送数据包加1 9 10 if (netif_msg_tx_done(db))11 dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);12 13 /* Queue packet check & send */14 if (db->tx_pkt_cnt > 0) //如果还有数据包,则继续发送15 dm9000_send_packet(dev, db->queue_ip_summed,16 db->queue_pkt_len);17 netif_wake_queue(dev); //启动发送队列18 }19 }
11.中断处理函数
网络设备接收数据的主要方法是有中断引发设备的中断处理函数,中断处理函数判断中断的类型,如果为接收中断,则读取接收到的数据,分配sk_buff数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区中,并调用netif_rx()函数将sk_buff传递给上层协议。
1 static irqreturn_t dm9000_interrupt(int irq, void *dev_id) 2 { 3 struct net_device *dev = dev_id; 4 board_info_t *db = netdev_priv(dev); 5 int int_status; 6 unsigned long flags; 7 u8 reg_save; 8 9 dm9000_dbg(db, 3, "entering %s\n", __func__);10 11 /* A real interrupt coming */12 13 /* holders of db->lock must always block IRQs */14 spin_lock_irqsave(&db->lock, flags);15 16 /* Save previous register address */17 reg_save = readb(db->io_addr);18 19 /* Disable all interrupts */20 iow(db, DM9000_IMR, IMR_PAR);21 22 /* Got DM9000 interrupt status */ //获取中断类型23 int_status = ior(db, DM9000_ISR); /* Got ISR */24 iow(db, DM9000_ISR, int_status); /* Clear ISR status */25 26 if (netif_msg_intr(db))27 dev_dbg(db->dev, "interrupt status %02x\n", int_status);28 29 /* Received the coming packet */ //接收到一个数据包30 if (int_status & ISR_PRS)31 dm9000_rx(dev); //调用数据接收函数32 33 /* Trnasmit Interrupt check */ //发送一个数据包34 if (int_status & ISR_PTS)35 dm9000_tx_done(dev, db); //调用数据发送函数36 37 if (db->type != TYPE_DM9000E) {38 if (int_status & ISR_LNKCHNG) {39 /* fire a link-change request */40 schedule_delayed_work(&db->phy_poll, 1);41 }42 }43 44 /* Re-enable interrupt mask */45 iow(db, DM9000_IMR, db->imr_all);46 47 /* Restore previous register address */48 writeb(reg_save, db->io_addr);49 50 spin_unlock_irqrestore(&db->lock, flags);51 52 return IRQ_HANDLED;53 }
12.接收数据
接收数据函数主要将接收到的数据包传递给上层。
1 dm9000_rx(struct net_device *dev) 2 { 3 board_info_t *db = netdev_priv(dev); //获得网卡私有数据首地址 4 struct dm9000_rxhdr rxhdr; 5 struct sk_buff *skb; 6 u8 rxbyte, *rdptr; 7 bool GoodPacket; 8 int RxLen; 9 10 /* Check packet ready or not */ 11 do { //存储器地址不变的读数据 12 ior(db, DM9000_MRCMDX); /* Dummy read */ //MRCMDX是内存数据预取读命令 13 14 /* Get most updated data */ 15 rxbyte = readb(db->io_data); 16 17 /* Status check: this byte must be 0 or 1 */ //0、1为正确,2表示接收出错 18 if (rxbyte & DM9000_PKT_ERR) { 19 dev_warn(db->dev, "status check fail: %d\n", rxbyte); 20 iow(db, DM9000_RCR, 0x00); /* Stop Device */ //关闭设备 并停止中断请求 21 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ 22 return; 23 } 24 25 if (!(rxbyte & DM9000_PKT_RDY)) // 0x01没准备好,直接返回 26 return; 27 28 /* A packet ready now & Get status/length */ 29 GoodPacket = true; 30 writeb(DM9000_MRCMD, db->io_addr); 31 //读取数据,从RX_SRAM读取到rxhdr中 32 (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); 33 34 RxLen = le16_to_cpu(rxhdr.RxLen); 35 36 if (netif_msg_rx_status(db)) 37 dev_dbg(db->dev, "RX: status %02x, length %04x\n", 38 rxhdr.RxStatus, RxLen); 39 40 /* Packet Status check */ //检查包得完整性 41 if (RxLen < 0x40) { 42 GoodPacket = false; 43 if (netif_msg_rx_err(db)) 44 dev_dbg(db->dev, "RX: Bad Packet (runt)\n"); 45 } 46 47 if (RxLen > DM9000_PKT_MAX) { 48 dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen); 49 } 50 51 /* rxhdr.RxStatus is identical to RSR register. */ 52 if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE | 53 RSR_PLE | RSR_RWTO | 54 RSR_LCS | RSR_RF)) { 55 GoodPacket = false; 56 if (rxhdr.RxStatus & RSR_FOE) { 57 if (netif_msg_rx_err(db)) 58 dev_dbg(db->dev, "fifo error\n"); 59 dev->stats.rx_fifo_errors++; 60 } 61 if (rxhdr.RxStatus & RSR_CE) { 62 if (netif_msg_rx_err(db)) 63 dev_dbg(db->dev, "crc error\n"); 64 dev->stats.rx_crc_errors++; 65 } 66 if (rxhdr.RxStatus & RSR_RF) { 67 if (netif_msg_rx_err(db)) 68 dev_dbg(db->dev, "length error\n"); 69 dev->stats.rx_length_errors++; 70 } 71 } 72 73 /* Move data from DM9000 */ //从DM9000获取数据 74 if (GoodPacket && //分配SKB 75 ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { //+4是因为除了数据包前面还有空读一字节、读状态一字节、读长度低位和高位各一个字节 76 skb_reserve(skb, 2); //定位data指针 DA(6)+SA(6)+type(2)+IP包+CFS(校验码4字节) IP包要求四字节对齐 77 rdptr = (u8 *) skb_put(skb, RxLen - 4); //定位tail指针 -4是减去校验码 78 79 /* Read received packet from RX SRAM */ 80 //读取数据 从RX SRAM 到sk_buff中 81 (db->inblk)(db->io_data, rdptr, RxLen); 82 dev->stats.rx_bytes += RxLen; 83 84 /* Pass to upper layer */ //获取上层协议类型 85 skb->protocol = eth_type_trans(skb, dev); 86 if (db->rx_csum) { 87 if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) 88 skb->ip_summed = CHECKSUM_UNNECESSARY; 89 else 90 skb->ip_summed = CHECKSUM_NONE; 91 } 92 netif_rx(skb); //把数据包交给上层 93 dev->stats.rx_packets++; 94 95 } else { 96 /* need to dump the packet's data */ 97 98 (db->dumpblk)(db->io_data, RxLen); 99 }100 } while (rxbyte & DM9000_PKT_RDY);101 }
可以看出接收数据主要包括:
判断为接收数据中断----dm9000_rx()完成更深入的数据包接收工作[获取数据包长度,分配sk_buff和数据段缓冲区,读取硬件接收的数据放入缓冲区中,解析上层协议类型,将数据包交给上层]