NET_IP_ALIGN 作用 usbnet异常分体(转)
1398/*
1399 * CPUs often take a performance hit when accessing unaligned memory
1400 * locations. The actual performance hit varies, it can be small if the
1401 * hardware handles it or large if we have to take an exception and fix it
1402 * in software.
1403 *
1404 * Since an ethernet header is 14 bytes network drivers often end up with
1405 * the IP header at an unaligned offset. The IP header can be aligned by
1406 * shifting the start of the packet by 2 bytes. Drivers should do this
1407 * with:
1408 *
1409 * skb_reserve(skb, NET_IP_ALIGN);
1410 *
1411 * The downside to this alignment of the IP header is that the DMA is now
1412 * unaligned. On some architectures the cost of an unaligned DMA is high
1413 * and this cost outweighs the gains made by aligning the IP header.
1414 *
1415 * Since this trade off varies between architectures, we allow NET_IP_ALIGN
1416 * to be overridden.
1417 */
1418#ifndef NET_IP_ALIGN
1419#define NET_IP_ALIGN 2
1420#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处的原因

浙公网安备 33010602011771号