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

在这里插入图片描述

一、mdio与rmii/sgmii

接上一篇文章《Linux—phy外设调试(一)》,在上一篇中我们说到我们还遗留了几个问题没有解释,其中提到的有mdio总线rmii/sgmii接口。我们需要先了解下这些接口硬件的概念。

首先什么是mdio总线?它是一种简单的双线串行接口,将管理器件(如MAC控制器、微处理器)与具备管理功能的收发器(如多端口吉比特以太网收发器或 10GbE XAUI收发器)相连接,从而控制收发器并从收发器收集状态信息。一般包含2个管脚:MDC和MDIO。MDC是管理数据的时钟输入,MDIO是管理数据的输入输出双向接口,数据是与MDC时钟同步的。

接着什么是rmii/sgmii接口?英文展开是Reduced Media Independent Interface/Serial Gigabit Media Independent Interface的缩写,翻译过来简化媒体独立接口/串行吉比特媒体独立接口,它是以太网媒体访问控制器(MAC)和物理层器件(PHY)的连接总线。如下图两个红圈所示:

在这里插入图片描述

二、主控mac控制器配置

我们知道外设phy芯片是与主控mac控制器进行通信交互的,所以调试phy我们需要打开主控mac控制器相关配置,以内核原生高通平台代码为例,在目录\drivers\net\ethernet\qualcomm\emac,我们打开对应目录Makefile文件见:

#
# Makefile for the Qualcomm Technologies, Inc. EMAC Gigabit Ethernet driver
#

obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o

qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o

同时我们看下emac.c有个emac_platform_driver结构体需要重点关注,当设备树中有对应匹配项,主控的mac控制器就会正常被驱动。这部分与phy芯片通过sgmii接口相互通信交互。

static struct platform_driver emac_platform_driver = {
	.probe	= emac_probe,
	.remove	= emac_remove,
	.driver = {
		.name		= "qcom-emac",
		.of_match_table = emac_dt_match,
		.acpi_match_table = ACPI_PTR(emac_acpi_match),
	},
};

三、phy driver与device的匹配规则

再回到我们关注的phy目录上/drivers/net/phy通过对应Makefile文件,我们知道配置CONFIG_PHYLIB宏,mdio_bus.c也会编译进内核。

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

在mdio_bus.c中有mdiobus_scan函数,在有phy driver或phy devices注册时会触发总线scan扫描:

int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{
... ...

	for (i = 0; i < PHY_MAX_ADDR; i++) {
		if ((bus->phy_mask & (1 << i)) == 0) {
			struct phy_device *phydev;

			phydev = mdiobus_scan(bus, i);
			if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) {
				err = PTR_ERR(phydev);
				goto error;
			}
		}
	}

... ...
}

struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
	struct phy_device *phydev;
	int err;

	phydev = get_phy_device(bus, addr, false);
... ...
}

在phy_device.c中我们可以看到,扫描完成后会拿到设备的phy_id

struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{
... ...

	r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
	if (r)
		return ERR_PTR(r);

	/* If the phy_id is mostly Fs, there is no device there */
	if ((phy_id & 0x1fffffff) == 0x1fffffff)
		return ERR_PTR(-ENODEV);

	return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}

拿到phy_id有什么用?,我们且看mdio_bus.c中,driver和devices的匹配规则,第一种是设备树匹配,第二种是driver中存在match_phy_device的方法,第三种就是设备的phy_id与driver支持的phy_id相匹配,就算匹配成功。(不同内核版本此处有差异)

static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
	struct phy_device *phydev = to_phy_device(dev);
	struct phy_driver *phydrv = to_phy_driver(drv);

	if (of_driver_match_device(dev, drv))
		return 1;

	if (phydrv->match_phy_device)
		return phydrv->match_phy_device(phydev);

	return (phydrv->phy_id & phydrv->phy_id_mask) ==
		(phydev->phy_id & phydrv->phy_id_mask);
}

正常在调试过程中我们可以查看内核文件系统/sys/bus/mdio_bus/节点下,是否有对应的driver以及识别到的phy设备。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值