• DM9000网卡驱动分析(转)


    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_DM9000B
    15 };
    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
    ", 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.
    ");
     20         return -ENOMEM;
     21     }
     22 //建立net_device到device的连接
     23     SET_NETDEV_DEV(ndev, &pdev->dev); 
     24 //内核输出信息
     25     dev_dbg(&pdev->dev, "dm9000_probe()
    ");
     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
    ");
     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
    ", 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)
    ", 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)
    ",
     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
    ");
     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
    ");
     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
    ");
     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
    ");
    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 the
    117          * 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 routine
    129          * 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_POLL
    144     db->flags |= DM9000_PLATF_SIMPLE_PHY;
    145 #endif
    146 
    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
    ", id_val);
    159     }
    160 
    161     if (id_val != DM9000_ID) {
    162         dev_err(db->dev, "wrong id: 0x%08x
    ", 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
    ", 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
    ", 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
    ", 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)
    ",
    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).
    ", 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
    ", dev->name);
     8 
     9     /* If there is no IRQ type specified, default to something that
    10      * 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.
    ");
    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); //复位DM9000
    22     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
    ", 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:
    ", __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 或 2
    15 
    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); //释放SKB
    34 
    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         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 *///设置发送数据的长度到TXPLLTXPLH中
    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
    ", 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
    ", __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
    ", 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
    ", 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
    ",
     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)
    ");
     45         }
     46 
     47         if (RxLen > DM9000_PKT_MAX) {
     48             dev_dbg(db->dev, "RST: RX Len:%x
    ", 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
    ");
     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
    ");
     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
    ");
     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和数据段缓冲区,读取硬件接收的数据放入缓冲区中,解析上层协议类型,将数据包交给上层]
  • 相关阅读:
    Redis总结
    设计模式-单例模式
    spring5源码解读
    关于asp.net MVC 中的TryUpdateModel方法
    WebSocket在ASP.NET MVC4中的简单实现 (该文章转自网络,经尝试并未实现,请大神指点。)
    C# 新特性 dynamic的使用及扩展
    C#用反射判断一个类型是否是Nullable同时获取它的根类型(转自网络)
    C#通用类型转换 Convert.ChangeType 转自网络
    浅谈.NET反射机制的性能优化 转自网络 博客园
    浅析大型网站的架构 转自软件中国
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5585231.html
Copyright © 2020-2023  润新知