记录学习总结,能力有限,仅供参考
rtl8363实现switch
一. 背景知识
A. RTL8363交换芯片的基本信息和功能
1. RTL8363支持:
每个端口都支持全双工
支持IEEE 802.1Q
VLAN支持4096个VLAN和32个额外VLAN
单芯片2+1端口10/100/1000M无阻塞交换机架构嵌入式2端口10/100/1000Base-T
PHY每个端口支持全双工10/100/1000M连接(仅在10/100M模式下支持半双工)
2. RTL8363结构图:
3. RTL8363框架图:
B. 相关网络背景知识
1. RTL8363使用的数据接口为rmii (限速100m)
RMII(Reduced Media Independent Interface)是一种常用的以太网物理层接口,用于将以太网 MAC(Media Access Control)层和 PHY(Physical Layer)层连接起来。它通常用于嵌入式系统中,使得系统可以通过以太网进行数据传输。
- 接口描述:
RMII接口使用4个信号线进行双向通信,分别是:TXD0、TXD1、RXD0、RXD1。
此外,还有一些辅助信号线,如:REFCLK(时钟信号)、CRS_DV(冲突检测/数据有效)、MDC(管理数据时钟)和 MDIO(管理数据输入/输出)。
(rtl8363不同模式接口下TXD0可能为RXD0,注意查看datasheet
)
2. SMI管理接口
包括MDC和MDIO两条引脚线。MDIO是一个PHY的管理接口,用来读/写PHY的寄存器,以控制PHY的行为或获取PHY的状态,MDC为MDIO提供时钟。
- mdio读写协议:
3. phy和mac
mac媒体访问控制子层协议,处于链路层向下部分
phy即物理层设备,向上对接mac
4. cpu与RTL8363连接模式为:固定模式(mac_to_mac)
-
固定模式(mac_to_mac)
mac_to_mac简而言之,需要手动固定一个虚拟phy设备连接。 -
phy模式(mac_to_phy)
5. RTL8363寄存器
现在datasheet都没有相关寄存器说明,都被提供的api接口封装了。phy id根据mdi高低电位选择。
二. U-boot下调试rtl8363
主控芯片arm:sigmastar ssd222d
Linux内核版本:Linux ubuntu 4.4.0-142-generic
网络文件:mdrv_emac.c
连接模式:rmii,mac_to_mac
A. U-boot下调试
1.boot下支持
- 打开RMII支持
- 添加编译rtl8363api库
2. boot下初始化phy设备
- 实现大体流程:
board_eth_init()-> MDrv_EMAC_initialize() ->MDrv_EMAC_PhyAddrScan() -> 获取phy_id,初始化phy
3. 虚拟phy设备
- 由于是mac_to_mac模式,跳过phy相关的操作
解决思路:虚拟phy设备
MDrv_EMAC_PhyAddrScan去扫描32个phy_id,在扫描完后将phy_id直接赋值为rtl8363的phy_id ,然后直接return phy_id,初始化rtl8363。后续phy读写所用phy地址都用此phy_id。
//phy扫描
void MDrv_EMAC_PhyAddrScan(void)
{
u32 word_ETH_MAN = 0x00000000;
MHal_EMAC_Write_JULIAN_0100(JULIAN_100_VAL);
ThisUVE.flagISR_INT_DONE = 0x00;
MHal_EMAC_read_phy(phy_id, PHY_REG_STATUS, &word_ETH_MAN);
if((0xffff != word_ETH_MAN)&&(0x0000 != word_ETH_MAN))
{
//printf("phy [%d]=%x\n",phy_id, word_ETH_MAN);
return;
}
for (phy_id = 0; phy_id < 32; phy_id++)
{
MHal_EMAC_read_phy(phy_id, PHY_REG_STATUS, &word_ETH_MAN);
if((0xffff != word_ETH_MAN)&&(0x0000 != word_ETH_MAN))
{
printf("find phy [%d]=%x\n",phy_id, word_ETH_MAN);
return;
}
}
printf("Can't get correct PHY Addr and reset to 0\n");
phy_id = 29;
}
,,,,,,
//初始化 phy
#ifdef CONFIG_ETHERNET_RTL8363
rtl8363_config_init();
#endif
,,,,,,
//phy读写 MDC_MDIO_PHY_ID =29;
MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP);
MDC_MDIO_READ(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_READ_REG, rData);
4. rtl8363提供的mdio读写api,需要将替换成平台mdio读写接口(smi.c)
/* MDC/MDIO, redefine/implement the following Macro */
#define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) MHal_EMAC_write_phy( MDC_MDIO_PHY_ID, regID, data)
#define MDC_MDIO_READ(preamableLength, phyID, regID, pData) MHal_EMAC_read_phy( MDC_MDIO_PHY_ID, regID, pData)
B. U-boot下问题排查
1. 接口验证
如果上述正常,但是在boot下还是网络不通,先验证rmii和MII管理接口是否正常
- rmii接口验证:
mdrv_emac下有打印rmii数据包的接口函数MDrv_EMAC_DumpMem,将MDrv_EMAC_tx接口更换MDrv_EMAC_DumpMem。
PC使用wireshark软件抓包,如果uboot下发的包与PC端抓的包一致,则通讯正常。
//if (ThisBCE.loopback == PHY_LOOPBACK)
// {
printf("Rx Data");
MDrv_EMAC_DumpMem((u32)packet, 0x40);
// }
// else if (ThisBCE.loopback == MAC_LOOPBACK)
// {
// MDrv_EMAC_tx(nic, (void *)packet, pktlen);
// }
// else
NetReceive((uchar *)packet, pktlen);
- SMI管理接口
用示波器查看MDC频率,rmii接口所需时钟频率为50Mhz.
通过MHal_EMAC_read_phy/MHal_EMAC_write_phy 调用mdio读写数据,用示波器查看波形是否正常. 波形和mdio读写协议进行对比。
不建议用系统指令去读写寄存器的值,因为没有rtl8363寄存器手册,你也不知道读出多少才是正确的。
避坑:这里只需验证波形是否和你要写的数据匹配,并不要需要关心是否能真正控制rtl8363,真正读写对应的寄存器是rtl8363提供的api实现。
如果上述接口有问题就需要去排除硬件问题,没有就需要验证代码问题。
- 在初始化rtl8363必要的硬复位是很有必要的,通过拉低再拉高NRESET脚引脚来硬件复位rtl8363.
- 根据实际情况配置rtk_macability参数,rmii最高支持100m。
- 根据datasheeet通过的phy_id修改api提供的读写接口。
将宏==MDC_MDIO_PHY_ID == datasheeet的phy_id=。
2. rtl8363初始化流程
硬件复位 -> rtk_switch_init(); -> 配置rtk_macability参数 ->end
3. uboot调试总结
建议接触先从uboot下理解phy怎么挂载在网卡上,实现网络互通。再在kernel下实现对rtl8363的开发。
由于是mac_to_mac,不用纠结MDrv_EMAC_PhyAddrScan扫描不到phy,只需理解phy是在mac的向下层,mactomac不经过phy,所以手动虚拟一个phy设备即可。
三. kernel下调试rtl8363
在uboot已经成功实现网络互通上,如果是傻瓜型,那在kernel只需配置引脚复用,在kernel下打开对rmii支持,设备树增加phy设备。即可在网络上互通。
由于需要实现软控制,选择dsa框架来实现。
A. dsa框架知识背景
1. dsa介绍
本质上是在链路层和网络层之间抽象出来的一层逻辑交换机。
2. dsa框架组成
DSA Switch:实现DSA框架的交换机设备。
DSA Master:DSA框架的主控节点,负责管理DSA Switch及其之间的通信,一般是网卡驱动。
DSA Slave:连接到DSA Switch的物理端口,负责转发数据包。
DSA Tag:标记数据包的源和目的信息,指示数据包应该从哪个端口发送和转发>到哪个端口。
3. phy驱动与switch驱动
- mac_to_phy模式选择phy驱动:
phy 驱动的核心功能是提供phy初始化接口,自动协商接口,以及状态读取接口(linkup,协商速率,等),不提供控制接口。 - mac_to_mac模式选择switch驱动:
switch 驱动核心功能是实现应用层配置vlan ,port等
4. 网络设备角度看
1703571336498)
B. rtl8363 switch驱动要实现的功能
1. 根据dsa_switch_ops结构体,根据实际需要实现相应接口
.get_tag_protocol:支持tagging协议
.probe:因为是虚拟phy,建议直接rutuen “驱动名”,表示支持该设备。
.setup: 当dsa驱动probe到设备,会调用该setup去配置和初始化设备。
.phy_read/.phy_write: switch的读写函数,根据平台不同去修改api底层接口。
例如:stmmac用的是stmmac_mdio_read,mdrv是MHal_EMAC_read_phy;
2. 增加attribute_group接口,方便应用层调试
增加一些接口来获取和设置rtl8363的配置。
例如: 获取rtl8363物理端口的连接状态
rtk_port_phyStatus_get
c. dsa设备树配置
1.设备树配置主要注意的是mdio和dsa的reg
- mdio: das的dsa,mii-bus一定要和网卡驱动的mdio是一个节点,因为dsa在probe需要同一mdio总线,发现mdio设备,此外dsa是通过这个mdiobus去find到网卡驱动注册的phy设备,否则dsa直接probe失败。
- switch:可见rlt8363结构图,phy1和phy3接rj45,其余默认配置即可
四. dsa的实现流程
A. DSA加载rtl8363 switch驱动
- dsa多次probe:当内核探测到新设备插入总线时,会遍历已注册的驱动程序列表,并调用与之匹配的驱动程序的probe函数。
1.网卡驱动注册phy流程:
网卡驱动先注册mdio总线,注册总线时会将设备类型和mdio_bus_class关联,关联之后,创建phy绑定总线为mdio总线
MDev_EMAC_init
MDev_EMAC_mii_init
of_mdiobus_register
mdiobus_register
bus->dev.class = &mdio_bus_class; //网络驱动的midobus归属于MDIO总线类设备,简而言之在mdio_bus_class下可以找到emac的mdiobus
mdiobus_scan
get_phy_device //手动返回phyid
phy_device_create // 创建虚拟phy
mdiodev = &dev->mdio;
mdiodev->dev.bus = &mdio_bus_type; //设备总线类型为mdio总线
phy_device_register
在sys文件系统下bus->dev.class = &mdio_bus_class的效果
在sys文件系统下mdiodev->dev.bus = &mdio_bus_type的效果
2.dsa probe phy流程:
dsa_probe
dsa_of_probe
mdio_bus = of_mdio_find_bus(mdio);
class_find_device(&mdio_bus_class, NULL, mdio_bus_np,
of_mdio_bus_match); //寻找mdio类设备 本质上判断dsa的bus是否也归属于mdioclass,所以这里需要设备树设置正确
dsa_setup_dst
dsa_switch_setup
dsa_switch_probe
name = ops->probe(parent, host_dev, sw_addr, priv); //调用rtl8363 probe
dsa_switch_setup_one
tag_protocol = ops->get_tag_protocol(ds); //设置tag协议,根据实际情况设置
dst->tag_ops = dsa_resolve_tag_protocol(tag_protocol);
dst->rcv = dst->tag_ops->rcv; //协议回调处理函数
ret = ops->setup(ds); // 调用rtl8363.setup初始化
dsa_slave_create // 创建switch port
dsa_cpu_dsa_setup //
of_phy_find_device //
bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);//在mdio总线下寻找固定连接phy
ds->ops->adjust_link(ds, port, phydev); //cpu port和emac 固定phy建立连接
genphy_update_link //更新链路
在sys文件系统下class_find_device的效果
在sys文件系统下bus_find_device的效果
在sys文件系统下mdio_bus_type下所有驱动
3.大体流程
B. DSA数据流
网络数据流:
MDev_EMAC_rx
napi_gro_receive
__netif_receive_skb
__netif_receive_skb_core
skb_vlan_untag
type = skb->protocol;// 获取网络数据协议
deliver_ptype_list_skb
deliver_skb
pt_prev->func(skb, skb->dev, pt_prev, orig_dev);//获取协议处理器的处理函数
// 如果switch驱动.get_tag_protocol不为0,那么网络数据会dsa的协议处理器.func = dsa_switch_rcv 处理。
//dsa处理完后又会调napi_gro_receive继续剥离数据heard
napi_gro_receive
,,,,
---> 网络层
dsa协议处理器
dsa_switch_setup_one
tag_protocol = ops->get_tag_protocol(ds); // 获取驱动协议
dst->tag_ops = dsa_resolve_tag_protocol(tag_protocol);
ops = dsa_device_ops[tag_protocol]; /*
const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
#ifdef CONFIG_NET_DSA_TAG_DSA
[DSA_TAG_PROTO_DSA] = &dsa_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_EDSA
[DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
[DSA_TAG_PROTO_TRAILER] = &trailer_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_BRCM
[DSA_TAG_PROTO_BRCM] = &brcm_netdev_ops,
#endif
#ifdef CONFIG_NET_DSA_TAG_QCA
[DSA_TAG_PROTO_QCA] = &qca_netdev_ops,
#endif
[DSA_TAG_PROTO_NONE] = &none_ops,
};*/
dst->rcv = dst->tag_ops->rcv;// 获取协议处理函数
DSA数据流和控制流图
五. dsa的使用
A. 应用层控制实例
略
B. 内核实现
略
相关资料链接:
【网络BSP开发经验】交换芯片驱动开发1(RTL8306MB交换芯片驱动开发)
https://blog.youkuaiyun.com/yy197696/article/details/129571370
//kernel dsa文档
https://www.kernel.org/doc/html/v5.15/networking/dsa/dsa.html
Linux 5.4内核Distributed Switch Architecture » Architecture翻译
https://blog.youkuaiyun.com/u010687717/article/details/124857859
网口扫盲二:Mac与Phy组成原理的简单分析
https://www.cnblogs.com/jason-lu/p/3196096.html
linux phy fixed-link
https://blog.youkuaiyun.com/u014044624/article/details/130670398?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-130670398-blog-124857859.235v38pc_relevant_default_base3&spm=1001.2101.3001.4242.1&utm_relevant_index=3
一文搞懂 Linux 网络 Phy 驱动
https://cloud.tencent.com/developer/article/2355036?from=15425
ARM与交换芯片mac_to_mac固定模式总结
https://blog.youkuaiyun.com/newbee_sccc/article/details/126266772
设备树 phy节点 使用说明
https://blog.youkuaiyun.com/weixin_45647912/article/details/108975862
phy 驱动与 switch 驱动
https://blog.youkuaiyun.com/agave7/article/details/106519019
Linux DSA Net Switch驱动开发
https://blog.youkuaiyun.com/Zhu_Zhu_2009/article/details/108654578
Linux 内核:设备驱动模型(3)class与device
https://www.cnblogs.com/schips/p/linux_device_model_3.html
以太网驱动的流程浅析(五)-mii_bus初始化以及phy id的获取
https://www.cnblogs.com/sky-heaven/p/11942921.html
STMMAC驱动
https://blog.youkuaiyun.com/qq_41076734/article/details/129163748
第十六章PHY -基于Linux3.10
https://blog.youkuaiyun.com/shichaog/article/details/44682931
linux驱动_sigmastar_SSD202D网络驱动简析
https://blog.youkuaiyun.com/gavinpeng/article/details/127104218
linux内核网络协议栈–netif_receive_skb()函数(八)
https://blog.youkuaiyun.com/qq_20817327/article/details/106752029