Linux---phy外设调试(一)

在这里插入图片描述

一、phy设备概述

我们知道在计算机网络上有一个OSI 7层模型:
在这里插入图片描述
应用层:网络服务与最终用户的一个接口。
协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP

表示层:数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)
格式有:JPEG、ASCll、EBCDIC、加密格式等 [2]

会话层:建立、管理、终止会话。(在五层模型里面已经合并到了应用层)
对应主机进程,指本地主机与远程主机正在进行的会话

传输层:定义传输数据的协议端口号,以及流控和差错校验。
协议有:TCP UDP,数据包一旦离开网卡即进入网络传输层

网络层:进行逻辑地址寻址,实现不同网络之间的路径选择。
协议有:ICMP IGMP IP(IPV4 IPV6)

数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验 [3] 等功能。(由底层网络定义协议)将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。

物理层:建立、维护、断开物理连接。(由底层网络定义协议)

后来人们觉得7层模型过于复杂又精简成5层或4层模型:
在这里插入图片描述今天我们的主角Phy设备处于最底层,也就是物理层。一般与数据链路层的mac芯片配合使用,在宏观上phy芯片主要是将模拟信号进行解码,通过MII等接口,将数字信号传送出去。
下图为一款DP83TC811 phy芯片的简单原理图,phy芯片与主控一般使用MII/RMII/RGMII接口进行数据传递。

在这里插入图片描述

同时主控一般使用Mdio总线去配置phy芯片的相关寄存器,有点类似于Codec芯片中PCM/I2S传输音频数据,I2C配置Codec寄存器。下图为该款芯片的一个典型应用图:
在这里插入图片描述
另外需要明确的一个点是phy是一个标准设备,必须符合IEEE802.3 中标准模块的相关规定,其中IEEE802.3 协议定义了地址为0-15 这16个寄存器的功能,地址16-31的寄存器留给芯片制造商自由定义。
也就是说phy芯片不是厂商想怎么设计就怎么设计的,你的符合标准,一旦有标准对于软件来讲就是利好,因为标准化的东西Linux内核已经给我们做好了,因此对于大多数phy芯片使用通用Generic PHY驱动就可以,对于有厂商自定义或者扩展寄存器的,才需要使用对应厂商的特殊驱动。

二、内核驱动配置与设备树添加

phy设备对应的内核目录为/drivers/net/phy通过分析各层Makefile文件,我们知道至少需要打开

obj-$(CONFIG_PHYLIB) += phy/

同时如果CONFIG_PHYLIB打开,对应目录一些文件也会编译进内核,其中包括phy_device.c等

libphy-y			:= phy.o phy_device.o mdio_bus.o mdio_device.o
obj-$(CONFIG_PHYLIB)		+= libphy.o

前面我们说到phy设备是一个标准设备,所以内核默认已经注册了缺省的默认phy驱动,在phy_device.c中:

... ...
static struct phy_driver genphy_driver[] = {
{
	.phy_id		= 0xffffffff,
	.phy_id_mask	= 0xffffffff,
	.name		= "Generic PHY",
	.soft_reset	= genphy_no_soft_reset,
	.config_init	= genphy_config_init,
	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
			  SUPPORTED_AUI | SUPPORTED_FIBRE |
			  SUPPORTED_BNC,
	.config_aneg	= genphy_config_aneg,
	.aneg_done	= genphy_aneg_done,
	.read_status	= genphy_read_status,
	.suspend	= genphy_suspend,
	.resume		= genphy_resume,
}, {
	.phy_id         = 0xffffffff,
	.phy_id_mask    = 0xffffffff,
	.name           = "Generic 10G PHY",
	.soft_reset	= gen10g_soft_reset,
	.config_init    = gen10g_config_init,
	.features       = 0,
	.config_aneg    = gen10g_config_aneg,
	.read_status    = gen10g_read_status,
	.suspend        = gen10g_suspend,
	.resume         = gen10g_resume,
} };

static int __init phy_init(void)
{
	int rc;

	rc = mdio_bus_init();
	if (rc)
		return rc;

	rc = phy_drivers_register(genphy_driver,
				  ARRAY_SIZE(genphy_driver), THIS_MODULE);
	if (rc)
		mdio_bus_exit();

	return rc;
}

static void __exit phy_exit(void)
{
	phy_drivers_unregister(genphy_driver,
			       ARRAY_SIZE(genphy_driver));
	mdio_bus_exit();
}

subsys_initcall(phy_init);
module_exit(phy_exit);

Generic PHYGeneric 10G PHY为内核缺省的默认phy驱动,里面有对标准phy驱动的初始化config_init函数软复位soft_reset函数参数协商配置config_aneg函数状态获取read_status函数,以及休眠唤醒相关的suspend/resume函数,对于一般的的phy设备就够用了,假设是一些非标或者扩展的,例如Atheros 803x PHY,需要使用其对应的驱动at803x.c,在宏配置上增加

obj-$(CONFIG_AT803X_PHY)	+= at803x.o

我们也可以看下at803x.c里面写的什么,打开可以看到驱动和通用驱动类似,但是有自己独立的实现,支持ATHEROS 8030/8031/8035 3款phy芯片:

static struct phy_driver at803x_driver[] = {
{
	/* ATHEROS 8035 */
	.phy_id			= ATH8035_PHY_ID,
	.name			= "Atheros 8035 ethernet",
	.phy_id_mask		= 0xffffffef,
	.probe			= at803x_probe,
	.config_init		= at803x_config_init,
	.set_wol		= at803x_set_wol,
	.get_wol		= at803x_get_wol,
	.suspend		= at803x_suspend,
	.resume			= at803x_resume,
	.features		= PHY_GBIT_FEATURES,
	.flags			= PHY_HAS_INTERRUPT,
	.config_aneg		= genphy_config_aneg,
	.read_status		= genphy_read_status,
	.ack_interrupt		= at803x_ack_interrupt,
	.config_intr		= at803x_config_intr,
}, {
	/* ATHEROS 8030 */
	.phy_id			= ATH8030_PHY_ID,
	.name			= "Atheros 8030 ethernet",
	.phy_id_mask		= 0xffffffef,
	.probe			= at803x_probe,
	.config_init		= at803x_config_init,
	.link_change_notify	= at803x_link_change_notify,
	.set_wol		= at803x_set_wol,
	.get_wol		= at803x_get_wol,
	.suspend		= at803x_suspend,
	.resume			= at803x_resume,
	.features		= PHY_BASIC_FEATURES,
	.flags			= PHY_HAS_INTERRUPT,
	.config_aneg		= genphy_config_aneg,
	.read_status		= genphy_read_status,
	.ack_interrupt		= at803x_ack_interrupt,
	.config_intr		= at803x_config_intr,
}, {
	/* ATHEROS 8031 */
	.phy_id			= ATH8031_PHY_ID,
	.name			= "Atheros 8031 ethernet",
	.phy_id_mask		= 0xffffffef,
	.probe			= at803x_probe,
	.config_init		= at803x_config_init,
	.set_wol		= at803x_set_wol,
	.get_wol		= at803x_get_wol,
	.suspend		= at803x_suspend,
	.resume			= at803x_resume,
	.features		= PHY_GBIT_FEATURES,
	.flags			= PHY_HAS_INTERRUPT,
	.config_aneg		= at803x_config_aneg,
	.read_status		= genphy_read_status,
	.aneg_done		= at803x_aneg_done,
	.ack_interrupt		= &at803x_ack_interrupt,
	.config_intr		= &at803x_config_intr,
} };

module_phy_driver(at803x_driver);

static struct mdio_device_id __maybe_unused atheros_tbl[] = {
	{ ATH8030_PHY_ID, 0xffffffef },
	{ ATH8031_PHY_ID, 0xffffffef },
	{ ATH8035_PHY_ID, 0xffffffef },
	{ }
};

MODULE_DEVICE_TABLE(mdio, atheros_tbl);

三、其他补充

其实phy这里还有很多需要讲的,例如phy芯片设备树的配置,例如mdio,rmii总线配置,软件层面phy驱动的注册及匹配,状态机维护及状态变化时相关函数的调用,应用层对网卡的操作及网络配置等,今天有点晚是写不完了,后面慢慢补充吧。


后面又补充了一篇虽然还是不太完整,但是一点一点逐步完善吧,希望对大家有帮忙《Linux—phy外设调试(二)

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值