文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>linux协议栈之链路层上的数据传输-----从网卡驱动..

linux协议栈之链路层上的数据传输-----从网卡驱动..

时间:2010-03-11  来源:cao5170

它主要完成:对网应对应的net net_device赋初值。并向内核调用register_netdev完成网络设备的注册,网络设备注册我们在上一节中已经说过,这里不再赘述。 看一下net_device中几个关键的函数: //在设备将打开的时候,调用此函数 netdev->open = e100_open; //在设备停用的时候调用此函数 netdev->stop = e100_close; //设备发送数据的时候调用此函数 netdev->hard_start_xmit = e100_xmit_frame; 到此时,网卡的初始化工作已经完成了。之后就可以操作网卡了。 那网卡应该怎么使用呢?必须首先唤起网卡,即使之UP,例如 ifconfig eth0 up 此时,内核会根据接口名字“eth0”找到对应的net_device.然后调用 net_device-> open.即:e100_open。 分析如下: static int e100_open(struct net_device *netdev) {          struct nic *nic = netdev_priv(netdev);          int err = 0;            //网卡正在UP,关闭载波信号          netif_carrier_off(netdev);          if((err = e100_up(nic)))                    DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");          return err; } 我们关心的是e100_up。跟踪如下: static int e100_up(struct nic *nic) {          int err;            //分配收包队列          if((err = e100_rx_alloc_list(nic)))                    return err;          //分配控制队列          if((err = e100_alloc_cbs(nic)))                    goto err_rx_clean_list;          //硬件初始化          if((err = e100_hw_init(nic)))                    goto err_clean_cbs;          //多播          e100_set_multicast_list(nic->netdev);          //开始接收数据          e100_start_receiver(nic);          mod_timer(&nic->watchdog, jiffies);          //注册中断例程          if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,                    nic->netdev->name, nic->netdev)))                    goto err_no_irq;          //启用中断          e100_enable_irq(nic);          netif_wake_queue(nic->netdev);          return 0;   err_no_irq:          del_timer_sync(&nic->watchdog); err_clean_cbs:          e100_clean_cbs(nic); err_rx_clean_list:          e100_rx_clean_list(nic);          return err; } 在此函数中,我们可以看到,它主要完成了:接立接收环形DMA缓冲区。注册了中断处理函数 关于环形DMA缓冲区接立是由e100_rx_alloc_list(nic)完成的 static int e100_rx_alloc_list(struct nic *nic) {          struct rx *rx;          // nic->params.rfds.count,接收缓存的总个数          unsigned int i, count = nic->params.rfds.count;          //rx_to_use:正在存在数据的位置          //rx_to_clean:数据的初始为止。所以。数据的有限位置是从rx_to_use到rx_to_use          nic->rx_to_use = nic->rx_to_clean = NULL;          if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))                    return -ENOMEM;          memset(nic->rxs, 0, sizeof(struct rx) * count);          //遍历并建立循环链表          for(rx = nic->rxs, i = 0; i < count; rx++, i++) {                    rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;                    rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1;                    if(e100_rx_alloc_skb(nic, rx)) {                             e100_rx_clean_list(nic);                             return -ENOMEM;                    }          }          //初始化起如位置为nic->rxs          nic->rx_to_use = nic->rx_to_clean = nic->rxs;            return 0; } 为设备建立DMA映射的主函数为e100_rx_alloc_skb().分析如下: static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) {          unsigned int rx_offset = 2; /* u32 align protocol headers */          if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + rx_offset)))                    return -ENOMEM;          /* Align, init, and map the RFD. */          rx->skb->dev = nic->netdev;          //在数据存储区之前空出offset空间 skb_reserve(rx->skb, rx_offset); //skb->data前部置RFD          memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));          //DMA内存映射,映射至skb->data          rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,                    RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);            /* Link the RFD to end of RFA by linking previous RFD to l        this one, and clearing EL bit of previous.  */ //初始化前一个skb中的控制信息          if(rx->prev->skb) {                    struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;                    put_unaligned(cpu_to_le32(rx->dma_addr),                             (u32 *)&prev_rfd->link);                    wmb();                    prev_rfd->command &= ~cpu_to_le16(cb_el);                    pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,                             sizeof(struct rfd), PCI_DMA_TODEVICE);          }            return 0; } 在这个函数里,主要完成了:DMA环形链表的建立。在这里涉及到了一个重要的数据结构sk_buff.稍后再给出它的结构分析。在这里我们只要知道在skb->data里储存的是接收数据就OK了。值得一提的是,Intel 100M 网卡对接收数据的处理,跟平时遇到的网卡不一样,接收数据时会由接收控制RU写入接收信息,由此判断接收是否完全等信息。也就是我们在代码里面看到的rfd.所以,在skb->data对应的就是rfd+网络传过来的数据. 到这里,接收准备工作已经完成了。   本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/luoye144200720102030/archive/2009/06/05/4243351.aspx
相关阅读 更多 +
排行榜 更多 +
弓箭手战士酷跑

弓箭手战士酷跑

飞行射击 下载
三角洲行动全面战场攀升A点进攻指南

三角洲行动全面战场攀升A点进攻指南

飞行射击 下载
僵尸射手世界大战

僵尸射手世界大战

飞行射击 下载