PHY驱动注册部分

PHY是IEEE 802.3规定的一个标准模块,MAC控制器可以通过MDIO对PHY进行配置或者读取phy相关状态,PHY内部寄存器必须满足

1 PHY芯片的寄存器地址空间是5位,一般由外部硬件连接决定。

2 地址空间031共32个寄存器,IEEE定义了0 - 15这16个寄存器的功能,16-31这16个寄存器由厂商自行实现。也就是说不管哪个厂商的PHY芯片,其中0~15这16个寄存器是一模一样的。 仅靠这 16个寄存器完全可以驱动起PHY芯片,至少能保证基本的网络数据通信。因此 Linux 内核有通用 PHY 驱动。所以 一般情况下,按道理来讲,不管你使用的哪个厂家的 PHY 芯片,都可以使用 Linux 的这个通用 PHY 驱动来验证网络工作是否正常。

如 寄存器0是PHY控制寄存器,通过Control Register可以对PHY的主要工作状态进行设置。 寄存器1是PHY状态寄存器,主要包含PHY的状态信息。等等 具体可以去找具体的寄存器信息,这里不做详细叙述。

如:

MAC控制器通过MDIO总线来管理phy设备,mdio总线与i2c总线类似,可以一个主机对应多个从设备,每个从设备都有地址。mdio最多接32个phy设备。

对应的目录是/sys/mdio,在/sys/mdio/devices目录中会有挂载在mdio的phy设备,在/sys/mdio/drivers中会有phy设备的驱动。

如:
 /sys/bus/mdio_bus/devices/stmmac-0:00 
其中 stmmac-0:00 表示 PHY 地址是 0。


该命令会读取 0~31 的所有寄存器,所以可以查看对应的寄存器值
cat /sys/bus/mdio_bus/devices/stmmac-0:00/phy_registers
root@OpenSDT:/sys/devices/platform/fe300000.ethernet/mdio_bus/stmmac-0/stmmac-0:00# cat phy_registers
 0: 0x1140
 1: 0x7989
 2: 0x1c
 3: 0xc982
 4: 0x1e1
 5: 0x0
 6: 0x64
 7: 0x2001
 8: 0x0
 9: 0xe00
10: 0x0
11: 0x0
12: 0x0
13: 0x0
14: 0x0
15: 0x2000
16: 0x23
17: 0x0
18: 0xffff
19: 0x0
20: 0x0
21: 0x0
22: 0xf00
23: 0xf00
24: 0x19c
25: 0x40
26: 0x5000
27: 0x802a
28: 0x0
29: 0x220
30: 0x0
31: 0x0
root@OpenSDT:/sys/devices/platform/fe300000.ethernet/mdio_bus/stmmac-0/stmmac-0:00# 

drivers\net\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,
	.aneg_done	= genphy_aneg_done,
	.suspend	= genphy_suspend,
	.resume		= genphy_resume,
	.set_loopback   = genphy_loopback,
};

	/*
不仅注册了mdio_bus总线,还注册了一个通用的PHY驱动作为缺省的内核PHY驱动,
但是如果PHY芯片的内部寄存器和802.3定义的并不一样或者需要特殊的功能配置
以实现更强的功能,这就需要专有的驱动。
*/
static int __init phy_init(void)
{
	int rc;

	//mdio 总线初始化注册:
	/*
		注册:
		/sys/class/mdio_bus
		/sys/bus/mdio_bus
	*/
	rc = mdio_bus_init();
	if (rc)
		return rc;

	//注册 名为    "Generic 10G PHY" phy驱动 到 mdio 总线
	rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE);
	if (rc)
		goto err_10g;

	//注册 名为   "Generic PHY" phy驱动 到 mdio 总线
	rc = phy_driver_register(&genphy_driver, THIS_MODULE);
	if (rc) {
		phy_driver_unregister(&genphy_10g_driver);
err_10g:
		mdio_bus_exit();
	}

	return rc;
}

static void __exit phy_exit(void)
{
	phy_driver_unregister(&genphy_10g_driver);
	phy_driver_unregister(&genphy_driver);
	mdio_bus_exit();
}

//这行的作用非常重要,这一行就决定了内核在启动的时候会调用该函数,注册完了之后紧接着又注册一个通用的PHY驱动
subsys_initcall(phy_init);
module_exit(phy_exit);

\drivers\net\phy\mdio_bus.c

// sys/class/mdio_bus
static struct class mdio_bus_class = {
	.name		= "mdio_bus",
	.dev_release	= mdiobus_release,
};


// /sys/bus/mdio_bus
struct bus_type mdio_bus_type = {
	.name		= "mdio_bus",
	.match		= mdio_bus_match,
	.uevent		= mdio_uevent,
};
EXPORT_SYMBOL(mdio_bus_type);

int __init mdio_bus_init(void)
{
	int ret;

	// 注册类
	// 即 /sys/class/mdio_bus
		ret = class_register(&mdio_bus_class);
		if (!ret) {
		
		//注册名为 "mdio_bus" 的总线。即注册 mdio 总线
		/*
		struct bus_type mdio_bus_type = {
			.name		= "mdio_bus",
			.match		= mdio_bus_match,
			.uevent		= mdio_uevent,
		};
		*/
		//即 /sys/bus/mdio_bus
		ret = bus_register(&mdio_bus_type);
		if (ret)
			class_unregister(&mdio_bus_class);
	}

	return ret;
}
EXPORT_SYMBOL_GPL(mdio_bus_init);


int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
{
	int retval;

/*
//phy 驱动
struct phy_driver
	.name		= "Generic PHY",
	 //MDIO 驱动通用部分
	 struct mdio_driver_common mdiodrv;-----+
											|
											|
											+---struct mdio_driver_common mdiodrv;
													int flags  |= MDIO_DEVICE_IS_PHY
													struct device_driver driver;
														.name		= "Generic PHY",
														//总线													//mdio 总线
														struct bus_type		*bus;-------------------------------struct bus_type mdio_bus_type = {
														int (*probe) (struct device *dev); = phy_probe              .name		= "mdio_bus",
														...                                                       	.match		= mdio_bus_match,
                                                                                                                  	.uevent		= mdio_uevent,
																													struct subsys_private *p;
																														//相关的驱动程序列表
																														struct kset *drivers_kset;

*/
	new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY;
	new_driver->mdiodrv.driver.name = new_driver->name;
	new_driver->mdiodrv.driver.bus = &mdio_bus_type;//驱动所挂载的总线类型 /sys/bus/mdio_bus
	new_driver->mdiodrv.driver.probe = phy_probe;//当匹配成功回调用的函数
	new_driver->mdiodrv.driver.remove = phy_remove;
	new_driver->mdiodrv.driver.owner = owner;


	new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS;

	retval = driver_register(&new_driver->mdiodrv.driver);
	if (retval) {
		pr_err("%s: Error %d in registering driver\n",
		       new_driver->name, retval);

		return retval;
	}

	pr_debug("%s: Registered new driver\n", new_driver->name);

	return 0;
}
EXPORT_SYMBOL(phy_driver_register);

所以 phy 驱动注册部分主要做了如下工作:

1 创建 初始化 struct phy_driver
2 设置struct phy_driver ,
如所在的名为“mdio_bus” 的mdio_bus_type 总线
如 匹配成功后的 probe()函数

3 注册 phy_driver

在这里插入图片描述

至此
phy_driver注册成功了,那就差phy_device的注册。看代码就知道 phy_device的注册不依靠设备树,而是在GMAC控制器注册时候 在其中的mdiobus_register中会注册phy_device 。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值