优化EtherCAT实时网卡驱动(创龙A40i板的千兆网卡)
目录
3)修改ethercat/devices/Kbuild.in
4)修改ethercat/devices/Makefile.am
5)修改网卡驱动sunxi-gmac-3.10-ethercat.c
(2)struct geth_priv私有结构体添加ec_device_t
一.generic通用模式的网卡驱动
优点:
- Linux以太网驱动程序涵盖的任何以太网硬件都可以用于EtherCAT。
- 无需修改实际的以太网驱动程序。
缺点:
- 性能比本地方法差一点,因为帧数据必须遍历网络堆栈的较低层。
二.修改本地网卡驱动
-
优点:
- 实时性比较好。
-
缺点:
- 需要修改以太网驱动程序。
-
优化原则:
- 跳过TCP/IP协议,即屏蔽netif_*接口
- 发送接收使用轮询,屏蔽中断
- 重复利用套接字缓冲区,原协议栈每发送接收一个包都要分配和释放套接字缓冲区
-
技巧
1. 获取网卡驱动源码
可以在linux源码中找到网卡驱动源码,比如我用的是创龙A40i核心板,全志A40i芯片,所以在linux-3.10/drivers/net/ethernet/allwinner目录下看到sunxi-gmac.c(1000兆网卡)和sun4i-emac.c(100兆网卡)。
2. 参考igh ethercat修改的网卡驱动
在ethercat/devices目录下,*-ethercat.c就是基于*-orig.c修改后的代码,比如r8169-3.10-ethercat.c就是基于r8169-3.10-orig.c修改后的代码,所以比较这两个文件,就知道修改了啥。
3. 参考igh ethercat官方文档
《igh-ethercat-1.5.2.pdf》的Ethernet Devices章节,4.7 Patching Native Network Drivers小节。
4. 屏蔽自动加载网卡驱动
修改内核编译选项,屏蔽自动加载网卡驱动
5. 了解Linux网卡驱动框架及DMA
可以自己查阅了解一下Linux网卡驱动,随便找一篇,大概了解框架就好,DMA也是。
我也是因为优化EtherCAT网卡驱动,第一次接触网卡驱动。
网卡驱动参考:http://t.csdnimg.cn/ML7id
DMA参考:https://blog.csdn.net/qq_41683305/article/details/124926572
修改详细说明
1)修改或添加的全部文件
2)获取1000兆网卡驱动源码
把linux-3.10/drivers/net/ethernet/allwinner目录的sunxi_gmac_ops.c,sunxi-gmac.c,sunxi-gmac.h复制到ethercat/devices目录下。
sunxi_gmac_ops.c文件名改为sunxi_gmac_ops-3.10.c;
sunxi-gmac.c复制两份,分别改为sunxi-gmac-3.10-ethercat.c和sunxi-gmac-3.10-orig.c;
sunxi-gmac.h复制两份,分别改为sunxi-gmac-3.10-ethercat.h和sunxi-gmac-3.10-orig.h;
说明:3.10为linux内核版本号
- 修改编译脚本
- 修改ethercat/configure.ac
添加编译sunxi-gmac选项,在./configure时可以使用 --enable-sunxi-gmac=yes编译sunxi-gmac,在676行添加以下代码:
#------------------------------------------------------------------------------
# ec-sunxi-gmac driver
#------------------------------------------------------------------------------
AC_ARG_ENABLE([sunxi-gmac],
AS_HELP_STRING([--enable-sunxi-gmac],
[Enable sunxi-gmac driver]),
[
case "${enableval}" in
yes) enable_sunxi_gmac=1
;;
no) enable_sunxi_gmac=0
;;
*) AC_MSG_ERROR([Invalid value for --enable-sunxi-gmac])
;;
esac
],
[enable_sunxi_gmac=0] # disabled by default
)
AM_CONDITIONAL(ENABLE_SUNXI_GMAC, test "x$enable_sunxi_gmac" = "x1")
AC_SUBST(ENABLE_SUNXI_GMAC,[$enable_sunxi_gmac])
AC_ARG_WITH([sunxi-gmac-kernel],
AC_HELP_STRING(
[--with-sunxi-gmac-kernel=<X.Y.Z>],
[sunxi-gmac kernel (only if differing)]
),
[
kernel_sunxi_gmac=[$withval]
],
[
kernel_sunxi_gmac=$linuxversion
]
)
if test "x${enable_sunxi_gmac}" = "x1"; then
AC_MSG_CHECKING([for kernel for sunxi-gmac driver])
kernels=`ls -1 ${srcdir}/devices/ | grep -oE "^sunxi-gmac-.*-" | cut -d "-" -f 3 | uniq`
found=0
for k in $kernels; do
if test "$kernel_sunxi_gmac" = "$k"; then
found=1
fi
done
if test $found -ne 1; then
AC_MSG_ERROR([kernel $kernel_sunxi_gmac not available for sunxi-gmac driver!])
fi
AC_MSG_RESULT([$kernel_sunxi_gmac])
fi
AC_SUBST(KERNEL_SUNXI_GMAC,[$kernel_sunxi_gmac])
比较如下:
3)修改ethercat/devices/Kbuild.in
添加编译的模块
比较如下:
4)修改ethercat/devices/Makefile.am
比较如下:
5)修改网卡驱动sunxi-gmac-3.10-ethercat.c
- 跳过TCP/IP协议,即屏蔽netif_*接口
- 发送接收使用轮询,屏蔽中断
- 重复利用套接字缓冲区,原协议栈每发送接收一个包都要分配和释放套接字缓冲区
(1)添加头文件
#include "../globals.h"
#include "ecdev.h"
(2)struct geth_priv私有结构体添加ec_device_t
(3)屏蔽netif_*和napi_*接口
netif_*是TCP/IP协议栈相关接口。
在代码中查找netif_,根据场景,屏蔽掉大部分的调用
NPAPI是一种硬中断触发+ Polling轮询收包机制。
屏蔽napi_enable,napi_disable,napi_gro_receive接口。
在geth_rx函数中,通过napi_gro_receive将 sk_buff 交付上层网络栈,但是我们不需要,所以屏蔽掉,调用igh提供的ecdev_receive接口。
重点说明:如果需要使用单缓存映射dma_map_single来访问DMA传输之间的数据,则必须以适当的方式在每次传输之间同步缓冲区,如果CPU需要访问缓冲区,可以通过dma_sync_sg_for_cpu()进行同步,如果设备需要,则调用dma_sync_sg_for_device()进行同步。
(4)屏蔽中断
在geth_probe函数中,把请求中断request_irq移到ecdev_open之后。
删除请求中断request_irq
调用ecdev_open函数,并屏蔽中断
(5)发送不释放skb_buff
因为发送由ethercat主站分配固定的skb_buff,循环利用,减少buff申请和释放时间。
geth_tx_complete函数:发送完成后不用释放skb_buff。
geth_xmit函数:发送失败不释放skb_buff,由ecrt_master_send函数最终调用。
(6)添加接收处理函数
ec_poll函数由ecrt_master_receive函数最终调用。
编译
编译成功后,在ethercat/devices目录下看到ec_sunxi_gmac.ko,拷贝到目标板上,执行以下命令加载ko:
insmod /lib/modules/ec_master.ko main_devices=00:00:00:00:00:00
insmod /lib/modules/ec_sunxi_gmac.ko
加载后通过lsmod查看:
-
优化后对比
1.关闭中断
可以通过cat /proc/interrupts命令才看前后中断号
优化前截图
优化后截图
2.扫描总线时间
优化前扫描时间大概为130ms
优化后扫描时间大概为80ms
优化前截图:
优化后截图:
3.执行时间
优化前:
开始最大执行时间为143us,半个小时后,最大执行时间为200us,平均为100us
优化后:
开始最大执行时间为105us,半个小时后,最大执行时间为113us,平均为75us
优化前截图:
开始截图
半小时后截图
优化后截图:
开始截图
半小时后截图
三.总结
跟通用模式的网卡驱动相对,优化后的网卡驱动实时性比较好,系统占用资源也少,因为跳过TCP/IP协议,屏蔽网卡中断,减少套接字缓冲区的分配和释放。
重点说明:如果需要使用单缓存映射dma_map_single来访问DMA传输之间的数据,则必须以适当的方式在每次传输之间同步缓冲区,如果CPU需要访问缓冲区,可以通过dma_sync_sg_for_cpu()进行同步,如果设备需要,则调用dma_sync_sg_for_device()进行同步。