博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
慢慢欣赏linux phy驱动初始化
阅读量:4068 次
发布时间:2019-05-25

本文共 7831 字,大约阅读时间需要 26 分钟。

设备树配置

enet0: ethernet@24000 {	phy-handle = <&phy0>;	tbi-handle = <&tbi0>;	phy-connect-type = "sgmii";	mdio@520 {		#address-cells = <1>;		#size-cells = <0>;		compatible = "fsl,gianfar-mdio";		reg = <0x520 0x20>;		phy0: ethernet-phy@10 {			interrupt-parent = <&mpic>;			interrupts = <10 1>;			reg = <0x10>;		};				tbi0: tbi-phy@11 {			reg = <0x11>;			device_type = "tbi-phy";		};	};}

代码流程

总入口,总线初始化

int __init phy_init(void)	{	int rc = mdio_bus_init();	=>int __init mdio_bus_init(void)	{		int ret = class_register(&mdio_bus_class);				ret = bus_register(&mdio_bus_type);	//mdio_bus总线注册		==>struct bus_type mdio_bus_type = {			.name		= "mdio_bus",			.match		= mdio_bus_match,			=>int mdio_bus_match(struct device *dev, struct device_driver *drv)			{	//phy驱动匹配则走probe,否则在ifconfig ethx阶段通过genphy_driver走probe				struct phy_device *phydev = to_phy_device(dev);				struct phy_driver *phydrv = to_phy_driver(drv);				return ((phydrv->phy_id & phydrv->phy_id_mask) ==					(phydev->phy_id & phydrv->phy_id_mask));			}			.pm		= MDIO_BUS_PM_OPS,		};	}	rc = phy_driver_register(&genphy_driver);	//通用phy驱动注册	==>struct phy_driver genphy_driver = {		.phy_id		= 0xffffffff,		.phy_id_mask	= 0xffffffff,		.name		= "Generic PHY",		.config_init	= genphy_config_init,		.features	= 0,		.config_aneg	= genphy_config_aneg,		.read_status	= genphy_read_status,		.suspend	= genphy_suspend,		.resume		= genphy_resume,		.driver		= {.owner= THIS_MODULE, },	};	=>int phy_driver_register(struct phy_driver *new_driver)	{		new_driver->driver.name = new_driver->name;		new_driver->driver.bus = &mdio_bus_type;		new_driver->driver.probe = phy_probe;		new_driver->driver.remove = phy_remove;		retval = driver_register(&new_driver->driver);//mdio_bus总线上的设备注册	}}

phy设备注册

int fsl_pq_mdio_init(void){	return of_register_platform_driver(&fsl_pq_mdio_driver);	==>struct of_platform_driver fsl_pq_mdio_driver = {		.name = "fsl-pq_mdio",		.probe = fsl_pq_mdio_probe,		.remove = fsl_pq_mdio_remove,		.match_table = fsl_pq_mdio_match,		==>struct of_device_id fsl_pq_mdio_match[] = {			{				.type = "mdio",				.compatible = "ucc_geth_phy",			},			{				.type = "mdio",				.compatible = "gianfar",			},			{				.compatible = "fsl,ucc-mdio",			},			{				.compatible = "fsl,gianfar-tbi",				},			{				.compatible = "fsl,gianfar-mdio", //与设备树匹配, 走fsl_pq_mdio_probe函数			},			{				.compatible = "fsl,etsec2-tbi",			},			{				.compatible = "fsl,etsec2-mdio",			},			{},		};	};}int fsl_pq_mdio_probe(struct of_device *ofdev,		const struct of_device_id *match) //解析设备树, 将phy的基本信息抽象出来作为phy设备注册{	struct mii_bus *new_bus = mdiobus_alloc();	new_bus->name = "Freescale PowerQUICC MII Bus",	new_bus->read = &fsl_pq_mdio_read,	new_bus->write = &fsl_pq_mdio_write,	new_bus->reset = &fsl_pq_mdio_reset,	new_bus->priv = priv;	fsl_pq_mdio_bus_name(new_bus->id, np);	addrp = of_get_address(np, 0, &size, NULL);	/* Set the PHY base address */	addr = of_translate_address(np, addrp);	map = ioremap(addr, size);	priv->map = map;	map -= offsetof(struct fsl_pq_mdio, miimcfg);	regs = map;	priv->regs = regs;	new_bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);	new_bus->parent = &ofdev->dev;	dev_set_drvdata(&ofdev->dev, new_bus);		err = of_mdiobus_register(new_bus, np);	=>int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)	{		/* Register the MDIO bus */		rc = mdiobus_register(mdio);		=>int mdiobus_register(struct mii_bus *bus)		{			bus->dev.parent = bus->parent;			bus->dev.class = &mdio_bus_class;			bus->dev.groups = NULL;			dev_set_name(&bus->dev, "%s", bus->id);			err = device_register(&bus->dev);			for (i = 0; i < PHY_MAX_ADDR; i++) {				if ((bus->phy_mask & (1 << i)) == 0) {	//这个流程走不到					struct phy_device *phydev;					phydev = mdiobus_scan(bus, i);					=>struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)					{						struct phy_device *phydev = get_phy_device(bus, addr);						err = phy_device_register(phydev);					}				}			}		}				for_each_child_of_node(np, child) {			/* A PHY must have a reg property in the range [0-31] */			addr = of_get_property(child, "reg", &len);			phy = get_phy_device(mdio, be32_to_cpup(addr));			rc = phy_device_register(phy);			=>struct phy_device * get_phy_device(struct mii_bus *bus, int addr)			{				struct phy_device *dev = NULL;				u32 phy_id;				int r = get_phy_id(bus, addr, &phy_id);	//通过mii_bus读取phyid				dev = phy_device_create(bus, addr, phy_id);				=>struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)				{					struct phy_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);					dev->speed = 0;					dev->duplex = -1;					dev->pause = dev->asym_pause = 0;					dev->link = 1;					dev->interface = PHY_INTERFACE_MODE_GMII;					dev->autoneg = AUTONEG_ENABLE;					dev->addr = addr;					dev->phy_id = phy_id;					dev->bus = bus;					dev->dev.parent = bus->parent;					dev->dev.bus = &mdio_bus_type;					dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL;					dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);					dev->state = PHY_DOWN;				}			}			=>int phy_device_register(struct phy_device *phydev)			{				err = device_register(&phydev->dev);			}					}	}}

phy设备初始化,假设phy设备为marvell,如果内核配置编译了phy的驱动

int marvell_init(void){	ret = phy_driver_register(&marvell_drivers[i]);	==>struct phy_driver marvell_drivers[] = {		.phy_id = 0x01410cc0,	//phydev通过get_phy_id读取的phyid,然后通过mdio_bus_match匹配		.phy_id_mask = 0xfffffff0,		.name = "Marvell 88E1111",		.features = PHY_GBIT_FEATURES,		.flags = PHY_HAS_INTERRUPT,		.config_init = &m88e1111_config_init,		.config_aneg = &marvell_config_aneg,		.read_status = &marvell_read_status,		.ack_interrupt = &marvell_ack_interrupt,		.config_intr = &marvell_config_intr,		.driver = { .owner = THIS_MODULE },	}	driver_register(&new_driver->driver);	=>int driver_register(struct device_driver *drv)	{		ret = bus_add_driver(drv);		=>int bus_add_driver(struct device_driver *drv)		{			error = driver_attach(drv);			=>int driver_attach(struct device_driver *drv)			{				return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);				=>int __driver_attach(struct device *dev, void *data)				{					driver_probe_device(drv, dev);					=>int driver_probe_device(struct device_driver *drv, struct device *dev)					{						ret = really_probe(dev, drv);						=>int really_probe(struct device *dev, struct device_driver *drv)						{							ret = drv->probe(dev);							=>int phy_probe(struct device *dev)							{								struct phy_device phydev = to_phy_device(dev);								struct device_driver *drv = get_driver(phydev->dev.driver);								struct phy_driver *phydrv = to_phy_driver(drv);								phydev->drv = phydrv;								phydev->supported = phydrv->features;								phydev->advertising = phydrv->features;								/* Set the state to READY by default */								phydev->state = PHY_READY;								if (phydev->drv->probe)	//一般为空									err = phydev->drv->probe(phydev);															}						}					}				}			}		}	}}

linux PHY驱动

https://blog.csdn.net/subfate/article/details/44900651

以太网驱动的流程浅析(五)-mii_bus初始化以及phy id的获取

https://cloud.tencent.com/developer/article/1545855

PHY Linux 驱动

https://blog.csdn.net/doitsjz/article/details/70331804

以太网PHY自动协商和其在Linux下的初始化

https://blog.csdn.net/kl1125290220/article/details/79859742

RMII模式下PHY的软件初始化流程

https://blog.csdn.net/fengying765/article/details/6762937

Linux网络子系统之---- PHY 配置

https://blog.csdn.net/jk198310/article/details/12909341

linux以太网驱动总结

https://blog.csdn.net/helloyizhou/article/details/72675533

Linux系统网卡驱动phy工作原理解析

https://blog.csdn.net/xwb1040885790/article/details/103880341

linux ethernet PHY 驱动

https://blog.csdn.net/jackjones_008/article/details/42004831

linux网络设备—mdio总线

https://blog.csdn.net/weixin_34138056/article/details/86449521

基于对zynq以太网驱动的分析理解linux phy子系统    好文

https://blog.csdn.net/xiangweiky/article/details/104345892

Linux网络子系统之---- PHY 配置

https://blog.csdn.net/a746742897/article/details/72876314

你可能感兴趣的文章
OS + Unix IBM Aix basic / topas / nmon / filemon / vmstat / iostat / sysstat/sar
查看>>
monitorServer nagios / cacti / tivoli / zabbix / SaltStack
查看>>
my ReadMap subway / metro / map / ditie / gaotie / traffic / jiaotong
查看>>
OS + Linux DNS Server Bind
查看>>
web test flow
查看>>
web test LoadRunner SAP / java / Java Vuser / web_set_max_html_param_len
查看>>
OS + UNIX AIX command
查看>>
OS + UNIX AIX performance
查看>>
OS + UNIX AIX Tools
查看>>
my ReadBook_liutongjingjixue / circulation economics
查看>>
my ReadBook_wangluoyingxiaoyucehua / network marketing / wangluoyingxiao
查看>>
db base database
查看>>
监控服务器端口,Down掉会自动重启,并发送邮件 Linux Shell
查看>>
Git提交错误:RPC failed; result=22, HTTP code = 411
查看>>
Druid使用ConfigFilter
查看>>
Elicpse使用技巧-打开选中文件文件夹或者包的当前目录
查看>>
eclips 运行项目内存不足的解决方案
查看>>
linux 挂载盘阵 smb
查看>>
漫谈 JAVA程序员、架构师、项目经理
查看>>
OPC品质类型
查看>>