一、共享网口NCSI的初始化
1.注册ncsi驱动
linux-5.4.11\drivers\net\ethernet\faraday\ftgmac.c
系统起来时,ftgmac100_probe函数,根据dts文件里的ncsi节点是否存在,判断是否需要加载ncsi驱动设备
linux-5.4.11\linux-5.4.11\arch\arm\boot\dts\aspeed-ast2600-evb.dts
所有ncsi驱动相关的代码都在linux-5.4.11\linux-5.4.11\net\ncsi目录下
先介绍几个结构体:
struct ncsi_dev_priv *ndp; 这个是一个总的ncsi驱动设备信息
struct ncsi_channel *hot_channel; /* Channel was ever active */曾经使用过的通道channel 信息
struct ncsi_package *active_package; /* Currently handled package */当前处理的package
struct ncsi_channel *active_channel; /* Currently handled channel */当前处理的channel
struct ncsi_request requests[256]; /* Request table */储存ncsi命令和结果
bool multi_package; /* Enable multiple packages */是否允许多个package
u32 package_whitelist; /* Packages to configure */允许的package,package 白名单
struct ncsi_package *np; 这个是package的信息,package可以理解为支持的ncsi网卡
bool multi_channel; /* Enable multiple channels */是否允许active多个channel
u32 channel_whitelist; /* Channels to configure */允许构建active的channel,channel白名单
unsigned int channel_num; /* Number of channels */网卡的总端口数
struct ncsi_channel *nc; 这个是channel的信息,channel可以理解为支持的ncsi网卡端口
struct ncsi_channel_mode modes[NCSI_MODE_MAX] channnel端口的某些信息,比如端口连接状态 NCSI_MODE_LINK
struct ncsi_cmd_arg nca; 这个是发送ncsi命令,组包的结构体
unsigned char package; /* Destination package ID */ncsi命令发往的package
unsigned char channel; /* Detination channel ID or 0x1f */ncsi命令发往的channel
unsigned char type; /* Command in the NCSI packet */ncsi命令的命令字
unsigned char *data; /* NCSI OEM data */ncsi厂商命令的数据段放在这
struct ncsi_request *nr; 这个是储存ncsi命令和结果的结构体
struct ncsi_request requests[256]; /* Request table */
ndp可以记录最近的256个ncsi命令及结果,以sk_buff的形式保存在*cmd,*rsp中
struct sk_buff *cmd; /* Associated NCSI command packet */
ncsi命令sk_buff
struct sk_buff *rsp; /* Associated NCSI response packet */
ncsi命令结果 sk_buff
2.ncsi驱动注册函数
ncsi_register_dev
- 注册ncsi工作队列
ncsi_dev_work
根据当前的state状态,执行不同的功能
ncsi_probe_channel 探测网卡端口的功能,一般网口up起来,或者网卡端口插上网线触发
ncsi_suspend_channel暂停端口的功能,一般在拔网线触发
ncsi_configure_channel构建active网卡端口的功能,一般在probe以后触发,或者端口自适应下拔网线failover另一个端口
2)注册ncsi报文接收处理函数
ncsi_rcv_rsp
Ncsi驱动接收到的控制报文主要分两类:
- aen报文,主要是通过插拔网线引起,由网卡发送给系统内核驱动处理,控制网卡端口连接状态
- 系统内核驱动发出ncsi命令以后,网卡返回的ncsi命令的响应报文
判断是否是aen报文,Packet type为NCSI_PKT_AEN 0xff,调用aen报文处理函数,aen报文的处理流程后面会讲
Ncsi命令响应报文,根据Packet type,调用ncsi命令响应处理函数
ncsi_rsp_handler 结构体(报文类型,命令的返回有效长度,ncsi命令响应处理函数)
Ncsi命令响应处理函数
Ncsi协议中定义的Packet type和代码中的是一致的
查询网卡端口信息(连接状态,速率等)的ncsi命令举例:
Ncsi命令类型Command Type 0x0a ncsi响应类型Response Type 0x8a
struct ncsi_pkt_hdr *hdr; 这个是ncsi命令头的结构体,和协议里面是一致的,16个字节
Ncsi命令响应处理函数
Ncsi命令响应包,代码里的结构体如下所示:
- 网口up起来,探测网卡package,构建active网卡端口channel
网口up,调用到linux-5.4.11\drivers\net\ethernet\faraday\ftgmac.c ftgmac100_open函数
如果使用的是phy驱动,调用phy_start(netdev->phydev);
如果使用的是ncsi驱动,调用ncsi_start_dev(priv->ndev);
更新ncsi驱动state状态,调用上文中提到的工作队列,根据当前的state状态,执行探测网卡package的功能
ncsi_dev_work –>ncsi_probe_channel,探测网卡package是通过发送一系列ncsi命令来实现的。我们可以称之为ncsi状态机的变化,具体可以参照协议和代码分析。
ncsi_probe_channel探测网卡package |
ncsi_choose_active_channel选择合适的网卡端口 |
ncsi_configure_channel构建active网卡端口 |
选择好package以后,就要继续选择channel,ncsi_probe_channel ->ncsi_choose_active_channel
选择合适的网卡端口默认策略是:从网卡第一个端口开始,判断网线是否连接,如果没有连接,继续遍历剩余端口;如果连接,便只构建active此端口;如果所有端口都没有连接网线,默认构建上次连接过网线的端口,之前没有连接过,active第一个端口。
选择好端口以后,就需要构建active网卡端口, ncsi_choose_active_channel-> ncsi_process_next_channel-> ncsi_configure_channel,channel的active也是通过发送一系列ncsi命令来实现的
记录hot_nc,之前连接过网线的端口的信息
至此,如果此端口连接着网线,网络就连通了。