全部博文(207)
分类: LINUX
2014-06-24 14:45:00
/*
* CPUs often take a performance hit when accessing unaligned memory
* locations. The actual performance hit varies, it can be small if the
* hardware handles it or large if we have to take an exception and fix it
* in software.
*
* Since an ethernet header is 14 bytes network drivers often end up with
* the IP header at an unaligned offset. The IP header can be aligned by
* shifting the start of the packet by 2 bytes. Drivers should do this
* with:
*
* skb_reserve(skb, NET_IP_ALIGN);
*
* The downside to this alignment of the IP header is that the DMA is now
* unaligned. On some architectures the cost of an unaligned DMA is high
* and this cost outweighs the gains made by aligning the IP header.
*
* Since this trade off varies between architectures, we allow NET_IP_ALIGN
* to be overridden.
*/
#ifndef
#define 2
#endif
以上是NET_IP_ALIGN的内核注释,位于kernel/include/linux/skbuff.h中。大意如下:
在访问未对齐的内存时,CPU常常会有一个性能冲击,这种能冲击在硬件能处理这种不对齐时能减小到很小;而如果这种不对齐的异常只能通过软件来处理,则会对性能产生较大冲击。由于一个以太网头部为14个字节,因而网络驱动经常在一个不对齐的偏移处结束这个网络头部。为了使这个头部能字对齐,可以将网络数据包的头部前移2字节。使用如下方法:
skb_reserve(skb, NET_IP_ALIGN);
这种偏移带来的不利在于DMA地址不对齐了。在某些架构上,这种DMA不对齐所带来的性能上的开销代价是很大的,这种代价带来的弊端远大于IP头对齐所带来的性能改善。这个是我们需要权衡的,因此我们使用一个宏来控制。
我们的代码集中讨论drivers/net/usb/usbnet.c文件和drivers/net/usb/sr9700.c文件。
usbnet.c在sr9700.c上层,sr9700.c是最底层与硬件交互的代码。
NET_IP_ALIGN在这里的作用是:要不使除去ip头部的14字节后的数据包4字节对齐,减轻后续软件的工作量,要不使包含头部的数据包首部4字节对齐,以利于DMA传输。
DMA传输一般都需要目的地址为4字节对齐,而skb = alloc_skb (size + NET_IP_ALIGN, flags)所分配的内存首地址是4字节对齐的。如果不进行skb_reserve(skb, NET_IP_ALIGN);即不保留前NET_IP_ALIGN字节无效,那么skb->data指针刚好是4字节对齐,利于USB的DMA传输。如果保留前NET_IP_ALIGN字节无效,那USB的DMA的首地址就不是4字节对齐了,但是由于IP头是14字节的(6+6+2)所以,IP头后面的数据包就刚好4字节对齐了。所以这需要一个取舍。
而我们的芯片中的USB使用的DMA现在使用的目的首地址必须是4字节边界对齐,在实现上的策略是无论传入什么地址,只是屏蔽最低2bit,后的地址作为目的地址,这就造成传入0xc80be002作为接收缓冲区的首地址,结果有效数据的头两个字节却出现在0xc80be000和0xc80be001处的原因