Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2762168
  • 博文数量: 79
  • 博客积分: 30130
  • 博客等级: 大将
  • 技术积分: 2608
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-22 14:58
个人简介

博所搬至http://xiaogr.com

文章存档

2015年(2)

2009年(3)

2008年(56)

2007年(18)

分类: LINUX

2007-10-23 16:08:58

------------------------------------------

本文系本站原创,欢迎转载!

转载请注明出处:http://ericxiao.cublog.cn/

------------------------------------------

它主要完成:对网应对应的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_userx_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+网络传过来的数据.

到这里,接收准备工作已经完成了。

阅读(3267) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~