Chinaunix首页 | 论坛 | 博客
  • 博客访问: 489208
  • 博文数量: 157
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 1608
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-16 09:30
文章存档

2010年(155)

2008年(2)

我的朋友

分类: LINUX

2010-03-11 20:19:21

它主要完成:对网应对应的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
阅读(649) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~