mdio总线用于链接mac和phy.其主要的code在drivers/net/phy/mdio_bus.c 中
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;
}
subsys_initcall(phy_init);
一般在phy_init中调用mdio_bus_init
int __init mdio_bus_init(void)
{
int ret;
ret = class_register(&mdio_bus_class);
if (!ret) {
ret = bus_register(&mdio_bus_type);
if (ret)
class_unregister(&mdio_bus_class);
}
return ret;
}
从mdio_bus_init中可以看到其主要是调用class_register(&mdio_bus_class);注册了一个设备类/sys/class/mdio_bus
static struct class mdio_bus_class = {
.name = "mdio_bus",
.dev_release = mdiobus_release,
};
如果设备类注册成功,则调用bus_register(&mdio_bus_type);注册一个总线类型/sys/bus/mdio
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
.pm = MDIO_BUS_PM_OPS,
};
在使用mdio bus前需要调用mdiobus_alloc申请一个mii_bus结构。那什么时候MII呢?
MII即媒体独立接口,它是IEEE-802.3定义的以太网行业标准。”媒体独立”表明在不对MAC硬件重新设计或替换的情况下,任何类型的PHY设备都可以正常工作。它包括一个数据接口,以及一个MAC和PHY之间的管理接口。
static inline struct mii_bus *mdiobus_alloc(void)
{
return mdiobus_alloc_size(0);
}
注意这里调用mdiobus_alloc_size的时候size是0
struct mii_bus *mdiobus_alloc_size(size_t size)
{
struct mii_bus *bus;
size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN);
size_t alloc_size;
int i;
//由于size是0,因此走else的case。也就是申请的size等于mii_bus的size.
/* If we alloc extra space, it should be aligned */
if (size)
alloc_size = aligned_size + size;
else
alloc_size = sizeof(*bus);
bus = kzalloc(alloc_size, GFP_KERNEL);
if (!bus)
return NULL;
bus->state = MDIOBUS_ALLOCATED;
//size为0,因此bus->priv 为null
if (size)
bus->priv = (void *)bus + aligned_size;
//一个mii_bus最多支持32个中断,这里的PHY_MAX_ADDR等于32
/* Initialise the interrupts to polling */
for (i = 0; i < PHY_MAX_ADDR; i++)
bus->irq[i] = PHY_POLL;
return bus;
}
申请mii_bus 后要调用mdiobus_register 来注册mii_bus,主要用于给mii_bus个个成员变量赋值.
#define mdiobus_register(bus) __mdiobus_register(bus, THIS_MODULE)
int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{
struct mdio_device *mdiodev;
int i, err;
if (NULL == bus || NULL == bus->name ||
NULL == bus->read || NULL == bus->write)
return -EINVAL;
BUG_ON(bus->state != MDIOBUS_ALLOCATED &&
bus->state != MDIOBUS_UNREGISTERED);
bus->owner = owner;
bus->dev.parent = bus->parent;
bus->dev.class = &mdio_bus_class;
bus->dev.groups = NULL;
dev_set_name(&bus->dev, "%s", bus->id);
//注册这个bus对应的device
err = device_register(&bus->dev);
if (err) {
pr_err("mii_bus %s failed to register\n", bus->id);
put_device(&bus->dev);
return -EINVAL;
}
mutex_init(&bus->mdio_lock);
//调用bus->reset 函数
if (bus->reset)
bus->reset(bus);
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;
}
}
}
bus->state = MDIOBUS_REGISTERED;
pr_info("%s: probed\n", bus->name);
return 0;
}
在__mdiobus_register 中除了注册bus->dev,最重要的就是针对每个phy调用mdiobus_scan得到对应的phy_device *phydev
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
{
struct phy_device *phydev;
int err;
//通过get_phy_device得到addr对应的phy_device,这里的addr是从0~32
phydev = get_phy_device(bus, addr, false);
if (IS_ERR(phydev))
return phydev;
/*
* For DT, see if the auto-probed phy has a correspoding child
* in the bus node, and set the of_node pointer in this case.
*/
of_mdiobus_link_mdiodev(bus, &phydev->mdio);
//注册这个phy_device *phydev
err = phy_device_register(phydev);
if (err) {
phy_device_free(phydev);
return ERR_PTR(-ENODEV);
}
return phydev;
}
int phy_device_register(struct phy_device *phydev)
{
int err;
//在mido_map这个数组中建立addr和struct mdio_device *mdiodev的对应关系 mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;
err = mdiobus_register_device(&phydev->mdio);
if (err)
return err;
//针对需要fixed的phy调用fixup->run。并设置phydev->has_fixups = true;
/* Run all of the fixups for this PHY */
err = phy_scan_fixups(phydev);
if (err) {
pr_err("PHY %d failed to initialize\n", phydev->mdio.addr);
goto out;
}
phydev->mdio.dev.groups = phy_dev_groups;
//添加phydev->mdio.dev 这个device
err = device_add(&phydev->mdio.dev);
if (err) {
pr_err("PHY %d failed to add\n", phydev->mdio.addr);
goto out;
}
return 0;
out:
mdiobus_unregister_device(&phydev->mdio);
return err;
}
--------------------- 本文来自 tiantao2012 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/tiantao2012/article/details/73087798?utm_source=copy
mdio总线
最新推荐文章于 2024-08-16 15:13:57 发布