9-Linux phy system

题图:gratisography

Linux phy system

PHY芯片为OSI的最底层-物理层(Physical Layer),通过MII与数据链路层的MAC芯片相连,对于MAC与PHY之间的一些知识可以查看Mac与Phy组成原理的简单分析,这篇文章进行熟悉。

PHY与MAC整体的连接框架:

连接框架

PHY的硬件系统算是比较复杂的,PHY与MAC相连,MAC与CPU相通,PHY与MAC通过MII和MDIO/MDC相连,MII是走网络数据的,MDIO/MDC是用来与PHY的寄存器通讯的,对PHY进行配置。类似的SWITCH芯片一般也有两种接口,MII用来走网络数据,SPI用来设置SWITCH的寄存器。

跟以前分析I2C/SPI的驱动一样,分为控制器驱动和设备器驱动。

1、控制器驱动

控制器的驱动使用的一样是platform总线的连接方式,在arch或dts下面进行对phy的platform进行add,platform_driver的register一般也放在/driver/net/phy/下面,device和driver的name匹配后就会执行platform_driver结构体所对应的probe接口,都大同小异,如下:

static struct platform_driver pfe_platform_driver = {
    .probe = pfe_platform_probe,
    .remove = pfe_platform_remove,
    .driver = {
        .name = "pfe",
#ifdef CONFIG_PM
        .pm = &pfe_platform_pm_ops,
#endif
    },
};


static int __init pfe_module_init(void)
{
    return platform_driver_register(&pfe_platform_driver);
}


static void __exit pfe_module_exit(void)
{
    platform_driver_unregister(&pfe_platform_driver);
}

MODULE_LICENSE("GPL");
module_init(pfe_module_init);
module_exit(pfe_module_exit);

因为phy与cpu的通讯配置使用的是MII、MDIO/MDC来进行传输控制的,所以probe函数里面如要对MII总线进行配置,最后调用mdiobus_register()of_mdiobus_register()对mdio_bus进行注册。

of_mdiobus_register()函数位于drivers/of/of_mdio.c中,该函数最后还是会调用mdiobus_register()函数,mdiobus_register()函数位于drivers\net\phy\mdio_bus.c中,通过一层一层的往下拨,会有如下结构:

 ‐‐> mdiobus_register
     ‐‐> device_register
     ‐‐> mdiobus_scan
         ‐‐> get_phy_device
             ‐‐> get_phy_id         // 读寄存器
                 ‐‐> phy_device_create  // 创建phy设备
                 ‐‐> INIT_DELAYED_WORK(&dev‐>state_queue, phy_state_machine); //初始化状态机

这边就是控制器和设备器的交接了,创建phy设备初始化PHY状态机,接下去就看设备器的驱动。

2、设备器驱动

设备器的驱动也是三个方面device、driver、bus。PHY的device接口为phy_device_registerphy_device_release,driver接口为phy_driver_registerphy_driver_unregister,bus接口为mdiobus_registermdiobus_unregister

这样一分析感觉就跟清晰了,有关PHY驱动的内容都位于/drivers/net/phy中。

phy的设备驱动不像i2c/spi有一个board_info函数进行添加设备,而是直接读取phy中的寄存器,根据IEEE的规定PHY芯片的前16个寄存器的内容必须是固定的,如下:


register

其中寄存器0x02和0x03即设备ID的高低位,每一种型号的PHY有其一串ID号,这我们查看对于的手册即可知道。

在设备的driver中使用MODULE_DEVICE_TABLE将对应的设备ID添加进入,他的效果可以理解为board_info函数所实现的内容,如broadcom的table:

static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
    { PHY_ID_BCM5411, 0xfffffff0 },
    { PHY_ID_BCM5421, 0xfffffff0 },
    { PHY_ID_BCM54210S, 0xfffffff0 },
    { PHY_ID_BCM5461, 0xfffffff0 },
    { PHY_ID_BCM5464, 0xfffffff0 },
    { PHY_ID_BCM5482, 0xfffffff0 },
    { PHY_ID_BCM5482, 0xfffffff0 },
    { PHY_ID_BCM50610, 0xfffffff0 },
    { PHY_ID_BCM50610M, 0xfffffff0 },
    { PHY_ID_BCM57780, 0xfffffff0 },
    { PHY_ID_BCMAC131, 0xfffffff0 },
    { PHY_ID_BCM5241, 0xfffffff0 },
    { }
};

MODULE_DEVICE_TABLE(mdio, broadcom_tbl);

phy_driver的register大概为如下一个过程,进行简单分析:

drivers/net/phy/phy_device.c
phy_init
    ‐‐> mdio_bus_init 注册mdio总线
       ‐‐> class_register(&mdio_bus_class);
       ‐‐> bus_register(&mdio_bus_type);
 ‐‐> phy_driver_register(&genphy_driver);

在mdio总线注册的时候会调用mdio_bus_match,如果match函数找到设备则会进行设备驱动的注册,match函数位于/drivers/net/phy/mdio_bus.c中,如下,进行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);
    
    printk("phydev->phy_id:%x ",phydev->phy_id);
    printk("phydrv->phy_id:%x \n",phydrv->phy_id);
    
    return ((phydrv->phy_id & phydrv->phy_id_mask) ==
        (phydev->phy_id & phydrv->phy_id_mask));
}

由log可以看出,设备dev的ID为600d8595,然后就去查找对应的驱动drv的ID,知道找到600d8595则进入probe函数。

[   23.306611] phydev->phy_id:600d8595 phydrv->phy_id:ffffffff
[   23.312150] phydev->phy_id:600d8595 phydrv->phy_id:ffffffff
[   23.317731] phydev->phy_id:600d8595 phydrv->phy_id:4dd072
[   23.323084] phydev->phy_id:600d8595 phydrv->phy_id:4dd033
[   23.328461] phydev->phy_id:600d8595 phydrv->phy_id:206070
[   23.333812] phydev->phy_id:600d8595 phydrv->phy_id:2060e0
[   23.339182] phydev->phy_id:600d8595 phydrv->phy_id:600d8595

这样找到ID后就会进行设备驱动的注册,对应的phy_driver_register()函数才能返回成功,才会执行phy_driver结构体下面的内容,如下:

static struct phy_driver bcm54210s_driver = {
    .phy_id     = PHY_ID_BCM54210S,
    .phy_id_mask    = 0xfffffff0,
    .name       = "Broadcom BCM54210S",
    .features   = PHY_GBIT_FEATURES |
              SUPPORTED_Pause | SUPPORTED_Asym_Pause,
    .flags      = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
    .config_init    = bcm54210s_config_init,
    .config_aneg    = bcm54210s_config_aneg,
    .read_status    = bcm54210s_read_status,
    .ack_interrupt  = bcm54xx_ack_interrupt,
    .config_intr    = bcm54xx_config_intr,
    .driver     = { .owner = THIS_MODULE },
};

里面对phy的寄存器等进行初始化配置,这边对PHY的驱动进行简单的介绍,关于PHY的内容还有好多,比如:PHY状态机ethtool工具这些都是在后面应用的时候需要用到的,等我自己深入研究后再进行学习总结。

Linux phy system的分析就到这边,有感悟时会持续会更新。

注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处,如有错误之处也请指出,进行探讨学习。文章只是起一个引导作用,详细的数据解析内容还请查看Linux相关教程,感谢您的查阅。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容