E1000驱动讨论

来源:互联网 发布:长春java试用期 编辑:程序博客网 时间:2024/05/08 21:07

 


作者: yaoma    时间: 2003-5-7 18:39     标题: ask

在网上传送的“包”与内部的sk_buff有什么区别呢
当一个网络设备从网上接收包时,它必须将接收的数据转换成 sk_buff 结构(这里使用的是什么函数)。
这些 sk_buff 则被网络驱动加入到了 backlog 队列中。


作者: blueflame    时间: 2003-5-8 09:19

网络上的一个包就对应一个skb.这个分配函数当然是alloc_skb(),至于调用它的时机,可能不同的驱动程序都会不同.我的网卡是Intel PRO/1000,驱动程序是e1000_main.c...,可以大概看看它是如何实现的.e1000_open(),这个函数做了一些很有意义的工作.比如分配了所有在发送和接收工作中需要的资源(包括配置8254x Transmit Unit,分配DMA内存IOremap网卡上的内存到虚拟空间,...),在操作系统内核里申请了中断请求(申请了SA_SHIRQ中断号对应的中断函数是e1000_intr()),准备好了watchdog定时器.值得注意的是设置了软中断TASKLET_SOFTIRQ,并赋予其函数为
e1000_alloc_rx_buffers(),也就是说每次中断到来的时候,软中断执行这个函数(这个我比较奇怪,它为什么会把分配skb放在软中断里去执行?)在那个函数里面:[/COlor]
1243     if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_2048) [/COlor]                 //ENET_HEADER_SIZE:14,CRC_LENTH:4       
[/COlor]1244         adapter->rx_buffer_len = E1000_RXBUFFER_2048;[/COlor]                      MAXIMUM_ETHERNET_PACKET_SIZE :1514[/COlor]
1245     else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_4096)[/COlor]   MINIMUM_ETHERNET_PACKET_SIZE :60
[/COlor]1246         adapter->rx_buffer_len = E1000_RXBUFFER_4096;
1247     else if((netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH) < E1000_RXBUFFER_8192)
1248         adapter->rx_buffer_len = E1000_RXBUFFER_8192;[/COlor]
可见对于一般的以太网的包,skb的大小是2k.
skb = alloc_skb(adapter->rx_buffer_len + reserve_len, GFP_ATOMIC);
reserve_len=2(一般来说是2,如果定义了ians高
级服务,则会是18)它的用途是保持skb与缓冲线对齐.GFP_ATOMIC表面分配工作不允许睡眠.[/Color]


作者: blueflame    时间: 2003-5-8 09:32

还有这个backlog其实只是一种网卡(3c...)实现的.在我的网卡里,是用的一种环adapter->[/Color]rx_ring.buffer_info.skb = skb;   buffer_info[]数组缺省是256,也就是说这个接收环里面有256个缓冲区(每个缓冲区对应一个skb),不过其实原理都差不多.


作者: yaoma    时间: 2003-5-8 09:43

谢谢你
是不是可以说在网上传播的都 是skb呢


作者: yaoma    时间: 2003-5-8 09:47

你的网驱动是自已加的吧,因为我在源码里没有见到
如何加呀,我也想把我的驱动加进去。


作者: blueflame    时间: 2003-5-8 10:37

网上传播的就是包阿,传播在每种网上的包都是有与该网络相应的格式的.操作系统接收到这些格式的包后把他们放在skb里面,skb里还有许多其他的结构,为的是方便各个协议处理到来的网络包.所以skb比包要丰富一些.
我的驱动不是自己加的.[/Color]


作者: ykwj121    时间: 2003-5-8 14:54

to blueflame:
我看的也是e1000的驱动,但和你说得非常不一样,你用的是哪个e1000的驱动,我用的intel的e1000-5.0.43的驱动,你呢?

你所说的软中断那段好象不太对吧,软中断应该是在/net/core/dev.c里面的netif_rx调起的,因此也不会在软中断里分配skb啊。

  1.         queue = &softnet_data[this_cpu];

  2.         local_irq_save(flags);

  3.         netdev_rx_stat[this_cpu].total++;
  4.         if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
  5.                 if (queue->input_pkt_queue.qlen) {
  6.                         if (queue->throttle)
  7.                                 goto drop;

  8. enqueue:
  9.                         dev_hold(skb->dev);
  10. //把skb挂到队列上去
  11.                         __skb_queue_tail(&queue->input_pkt_queue,skb);
  12.                         /* Runs from irqs or BH's, no need to wake BH */
  13. //这里开始交给软中断去处理
  14.                         cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
  15.                         local_irq_restore(flags);
复制代码



而在net_dev_init里面已经指定:

  1. //中断处理函数net_tx_action
  2.         open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
  3. //中断处理函数net_rx_action
  4.         open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
复制代码

作者: blueflame    时间: 2003-5-8 17:59

奇怪,我看的代码怎么不一样,我的是intel pro/1000网卡
dmesg |grep -i pro
Intel(R) PRO/1000 Network Driver - version 4.1.7
Intel(R) PRO/1000 Network Connection
在drivers/addon/e1000/e1000_main.c文件里面:
86 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
87
88 /* Driver version */
89 char e1000_driver_version[] = "4.1.7";
所以肯定是这个驱动程序.[/Color]


作者: blueflame    时间: 2003-5-8 18:05

而这个驱动的也肯定是用的软中断分配的skb.函数e1000_open()调用e1000_setup_rx_resources(),在该函数里面调用
tasklet_init(&adapter->
rx_fill_tasklet, e1000_alloc_rx_buffers,(unsigned long) adapter);tasklet_schedule(&adapter->rx_fill_tasklet);
e1000_alloc_rx_buffers()就是软中断要执行的函数,在这里会分配skb,当然中断函数里面如果发现环上有1/4的unused缓冲区,也会主动触发这个软中断.yhwj121:你看的是哪个文件阿?[/Color]


作者: ykwj121    时间: 2003-5-9 09:02

我一般都是直接从intel下载编译驱动的,我看过3.*.*(不记得是多少了)的一个驱动,然后是4.3.15,然后现在是5.0.43驱动,如果可以的话,你也去下一个吧,模式和你说得不太一样。而里面没有4.1.7的驱动了,所以我也没办法去看你所说的那种软中断模式。
下载页面:
http://downloadfinder.intel.com/ ... asp?FileName=e1000-

intel后来的驱动性能是越来越棒了,不过也加了很多我并不关心的东西,一般来说,我都只看e1000_main.c,我记得以前的驱动都只有一个e1000_main.c的文件的,现在其他的文件越来越多了,呵呵。不过我觉得intel的千兆驱动写得很不错,值得作为学习对象的。


作者: blueflame    时间: 2003-5-9 09:20

请问,网卡硬件是怎么把数据传给内核的.在我的版本中,我只看到两个地方.一个是:
3136         adapter->rx_ring.buffer_info.dma = pci_map_single(pdev, skb->data, adapter->rx_buffer_len, PCI_DMA_FROMDEVICE);//全部指向skb->data
3140         rx_desc->buffer_addr = cpu_to_le64(adapter->rx_ring.buffer_info.dma);                                               
3143             E1000_WRITE_REG(&adapter->shared, RDT, i);        将i写入寄存器RX Descriptor Tail
一个是E1000_WRITE_REG(&adapter->shared, RDBAL, adapter->rx_ring.dma);
她将将e1000_rx_desc管理数组的物理地址写入了相应的网卡寄存器中,可管理数组还不是存放skb的缓冲区数组阿
关键的操作在哪里?[/Color]


作者: blueflame    时间: 2003-5-9 10:09

我知道了,我们说的代码的位置不一样,你写出来的那个是在netif_rx()中,所有的网卡驱动都会调用这个函数.我说的是网卡驱动在调用netif_rx()之前的一些处理工作.还有其实我那么说可能会使人误会,其实在软中断中分配skb是超前做好准备的意思[/Color]


作者: ykwj121    时间: 2003-5-9 12:32

A)在5.0.43版本里面的e1000_setup_rx_resources没有软中断,在这里面只是预先分配好了DMA缓冲数据的空间:
//rxdr->count对应的应该是装载驱动的RxDescriptors,缺省是256
size = sizeof(struct e1000_buffer) * rxdr->count;
rxdr->buffer_info = kmalloc(size, GFP_KERNEL);
if(!rxdr->buffer_info) {
        return -ENOMEM;
}
memset(rxdr->buffer_info, 0, size);

在e1000.h里面说明了e1000_buffer,里面是一个sk_buff指针skb,不是实际为skb分配了空间:
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
        struct sk_buff *skb;
        uint64_t dma;
        unsigned long length;
        unsigned long time_stamp;
};

B)在e1000_up里面进行了e1000_alloc_rx_buffers,这时候准备了skb,且通过pci_map_single将skb->data通过memmap到了DMA上。
C)准备工作里还做了中断设置,中断函数为e1000_intr。
D)在收到的数据的时候,中断处理函数e1000_intr会进行pci_unmap_single,这时候已经把数据传送network stack了。其实里面关键就在memmap上,通过这个实现零拷贝。


作者: ykwj121    时间: 2003-5-9 12:34

再次建议你读新驱动 ,这样我们比较好交流:w


作者: blueflame    时间: 2003-5-9 14:38

我用的不是我的机子,所以不好随便升级网卡驱动.,我看了一下你贴出来的部分代码,觉得和我的版本的基本相似.我不清楚DMA部分.我现在只是在映射的基础上自己觉得应该是好像弄懂了(傻笑).只是你说的分配的那个DMA缓冲数据的空间,我的理解是只是分配了e1000_rx_desc结构数组所占的空间.这个数组中的每个元素管理一个缓冲区..在e1000_configure_rx()中E1000_WRITE_
REG(&adapter->shared, RDBAL, adapter->rx_ring.dma);将e1000_rx_desc管理数组的物理地址写入了相应的网卡寄存器中,E1000_WRITE_REG(&adapter->shared, RDT, i);这样,网卡硬件就能够得到e1000_rx_desc的值.而它的第一项就是buffer_addr,指向skb->data.我打算去看看DMA的知识.[/COlor]


作者: blueflame    时间: 2003-5-9 14:45

1514     tasklet_init(&adapter->rx_fill_tasklet, e1000_alloc_rx_buffers,
                  (unsigned long) adapter);

     tasklet_schedule(&adapter->rx_fill_tasklet);
我的版本的e1000_open()里面有这么两项,所以我说用软中断来准备分配skb.不知道新版本的skb在哪里准备的.我倒觉得这样挺好的,提前分配的话毕竟节省了点中断时候的压力[/Color]


作者: ykwj121    时间: 2003-5-9 16:00

嘿嘿,你没有看明白我的意思。
我的意思是,新版本里面虽然没有软中断,但也是在e1000_up(这个是函数在e1000_open里面调的,基本上和你的一样)里面调用了e1000_alloc_rx_buffers来提前准备skb的。后来每次用了这个skb以后也会再提前准备的。

你不用e1000-5.0.43,可以直接下代码看啊:w
新的驱动真的写得比以前要好。再积极建议一下。


作者: blueflame    时间: 2003-5-9 23:37

嘿嘿,我可没那么多时间看这个了,所以只能跟你用说得.不好意思啊,只是open函数也不是每次都调用的,总得是设备up的时候才调吧.所以e1000_alloc_rx_buffers还应该在某个函数里面才能经常被调才是[/Color]


作者: ykwj121    时间: 2003-5-12 09:00

呵呵,这个也说过了。
我在上个帖子里面说了“后来每次用了这个skb以后也会再提前准备的”,也就是说后来会继续调用e1000_alloc_rx_buffers来提前准备skb空间。我的版本里是在e1000_clean_rx_irq里面调用的。


作者: blueflame    时间: 2003-5-12 10:32

刚才去下载了5.0.43版本的驱动源码大概看了一点.觉得确实比以前的版本要简洁.正如你所说,它没有为分配skb特意去设个软中断.而是一开始up()的时候allocrxbuffers.然后每次中断程序里面中的e1000_clean_rx_irq结束前allocrxbuffers一下.

        for(i = 0; i < E1000_MAX_INTR; i++)
                if(!e1000_clean_rx_irq(adapter) &&
                   !e1000_clean_tx_irq(adapter))
                        break;
的意思是不是说如果可能的话,一次中断处理10个到来的数据包.adapter->rx_int_delay这个的意思是延迟接收接收中断的时间,当然中断太频繁的时候这个意义很明显,可是如果中断不频繁,也就是说在一定的时间里面没有凑足10个中断它是采取什么机制来让这些中断发出去呢,是不是就是rx_int_delay这个数值作为定时器.还是另外有别的定时器[/Color]


作者: ykwj121    时间: 2003-5-12 11:24

E1000_MAX_INTR与中断次数无关,这应该是尝试e1000_clean_rx_irq的次数而已,如果连续调用e1000_clean_rx_irqE1000_MAX_INTR次都返回失败的话,就不再尝试了。
而e1000_clean_rx_irq里面可以看到,返回失败的关键就在:
while(rx_desc->status & E1000_RXD_STAT_DD) {

                cleaned = TRUE;
。。。。
}
只要rx_desc->status & E1000_RXD_STAT_DD,返回值cleaned就是成功了。而cleaned缺省是false的。

而你说的rx_int_delay是对应下面这个驱动参数的RxIntDelay,我把驱动程序的README里面的这一段摘出来给你看,这个间隔两个中断之间时间用的。
RxIntDelay
Valid Range: 0-65535 (0=off)
Default Value: 0
    This value delays the generation of receive interrupts in units of 1.024
    microseconds.  Receive interrupt reduction can improve CPU efficiency if
    properly tuned for specific network traffic. Increasing this value adds
    extra latency to frame reception and can end up decreasing the throughput
    of TCP traffic. If the system is reporting dropped receives, this value
    may be set too high, causing the driver to run out of available receive
    descriptors.


作者: blueflame    时间: 2003-5-12 15:09

谢谢.那Rxintdelay就是说两次中断之间的最高频率了??开始我还以为E1000_MAX_INTR就是单个"中断"的最多次数.那从e1000_clean_rx_irq()中看出一次真正中断最多能储存rx_ring->count个数据包,是不是?还是说小于该数值的一个硬件规定的数目[/Color]


作者: ykwj121    时间: 2003-5-12 17:55

恩,rx_ring->count应该就是网卡可以缓冲的包的个数,对应的是readme里面的RxDescriptors.

RxDescriptors
Valid Range: 80-256 for 82542 and 82543-based adapters
             80-4096 for 82540, 82544, 82545, and 82546-based adapters
Default Value: 256
    This value is the number of receive descriptors allocated by the driver.
    Increasing this value allows the driver to buffer more incoming packets.
    Each descriptor is 16 bytes.  A receive buffer is also allocated for each
    descriptor and can be either 2048, 4096, 8192, or 16384 bytes, depending
    on the MTU setting. The maximum MTU size is 16110.




欢迎光临 Linux伊甸园论坛 (http://www.linuxeden.com/forum/)Powered by Discuz! 7.2
原创粉丝点击