下面这段code 可以看清struct phy_device *phy 注册的流程
phy = get_phy_device(mdio, addr, is_c45);
if (!phy || IS_ERR(phy))
return -EIO;
phy->irq = mdio->irq[addr];
/* All data is now stored in the phy struct;
* register it
*/
rc = phy_device_register(phy);
if (rc) {
phy_device_free(phy);
return -ENODEV;
}
这样注册之后就可以在具体的调用module_phy_driver 来注册对应的phy driver.
这里面涉及两个重要的函数,一个是get_phy_device,一个是phy_device_register。
我们先看第一个get_phy_device
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{
struct phy_c45_device_ids c45_ids = {0};
u32 phy_id = 0;
int r;
//调用get_phy_id 得到phy id,将结果保存在phy_id 中,可见是一个u32 类型的值
r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
//r不为null的话,说明没有正确得到了phy id,直接返回
if (r)
return ERR_PTR(r);
//如果phyid 为0x1fffffff,说明没有phy device,直接返回
/* If the phy_id is mostly Fs, there is no device there */
if ((phy_id & 0x1fffffff) == 0x1fffffff)
return ERR_PTR(-ENODEV);
//如果得到phy id的话,则create 这个device
return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}
static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
bool is_c45, struct phy_c45_device_ids *c45_ids)
{
int phy_reg;
if (is_c45)
return get_phy_c45_ids(bus, addr, phy_id, c45_ids);
/* Grab the bits from PHYIR1, and put them in the upper half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
if (phy_reg < 0)
return -EIO;
*phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
if (phy_reg < 0)
return -EIO;
*phy_id |= (phy_reg & 0xffff);
return 0;
}
从get_phy_id 中可以看到phy_id 是由两个16为的MII_PHYSID1和MII_PHYSID2 组合起来的。都是通过mdiobus_read来读取的
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{
int retval;
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
retval = bus->read(bus, addr, regnum);
mutex_unlock(&bus->mdio_lock);
return retval;
}
mdiobus_read中就直接调用bus->read
而这里的mii_bus *bus的read一般是mdio driver中实现
例如:
static int hns_mdio_probe(struct platform_device *pdev)
{
struct hns_mdio_device *mdio_dev;
struct mii_bus *new_bus;
struct resource *res;
int ret = -ENODEV;
if (!pdev) {
dev_err(NULL, "pdev is NULL!\r\n");
return -ENODEV;
}
mdio_dev = devm_kzalloc(&pdev->dev, sizeof(*mdio_dev), GFP_KERNEL);
if (!mdio_dev)
return -ENOMEM;
new_bus = devm_mdiobus_alloc(&pdev->dev);
if (!new_bus) {
dev_err(&pdev->dev, "mdiobus_alloc fail!\n");
return -ENOMEM;
}
new_bus->name = MDIO_BUS_NAME;
new_bus->read = hns_mdio_read;
new_bus->write = hns_mdio_write;
new_bus->reset = hns_mdio_reset;
new_bus->priv = mdio_dev;
new_bus->parent = &pdev->dev;
}
回到get_phy_device 中通过mdio driver得到phy id后,就通过phy_device_create 来create 这个设备
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
bool is_c45,
struct phy_c45_device_ids *c45_ids)
{
struct phy_device *dev;
struct mdio_device *mdiodev;
//申请phy_device *dev
/* We allocate the device, and initialize the default values */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
//dev->mdio的赋值
mdiodev = &dev->mdio;
mdiodev->dev.release = phy_device_release;
mdiodev->dev.parent = &bus->dev;
mdiodev->dev.bus = &mdio_bus_type;
mdiodev->bus = bus;
mdiodev->pm_ops = MDIO_BUS_PHY_PM_OPS;
mdiodev->bus_match = phy_bus_match;
mdiodev->addr = addr;
mdiodev->flags = MDIO_DEVICE_FLAG_PHY;
mdiodev->device_free = phy_mdio_device_free;
mdiodev->device_remove = phy_mdio_device_remove;
// 要求上层insmod 这个driver对应的ko
request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
//初始化这个mdiodev->dev
device_initialize(&mdiodev->dev);
return dev;
}
最后回到最前面,当成功创建phy对应的device后调用phy_device_register 注册device
int phy_device_register(struct phy_device *phydev)
{
int err;
err = mdiobus_register_device(&phydev->mdio);
if (err)
return err;
/* 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;
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;
}
phy_device_register 主要是把phy device注册到MDIO bus没,这样就会调用phy driver的probe函数了
phy = get_phy_device(mdio, addr, is_c45);
if (!phy || IS_ERR(phy))
return -EIO;
phy->irq = mdio->irq[addr];
/* All data is now stored in the phy struct;
* register it
*/
rc = phy_device_register(phy);
if (rc) {
phy_device_free(phy);
return -ENODEV;
}
这样注册之后就可以在具体的调用module_phy_driver 来注册对应的phy driver.
这里面涉及两个重要的函数,一个是get_phy_device,一个是phy_device_register。
我们先看第一个get_phy_device
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
{
struct phy_c45_device_ids c45_ids = {0};
u32 phy_id = 0;
int r;
//调用get_phy_id 得到phy id,将结果保存在phy_id 中,可见是一个u32 类型的值
r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
//r不为null的话,说明没有正确得到了phy id,直接返回
if (r)
return ERR_PTR(r);
//如果phyid 为0x1fffffff,说明没有phy device,直接返回
/* If the phy_id is mostly Fs, there is no device there */
if ((phy_id & 0x1fffffff) == 0x1fffffff)
return ERR_PTR(-ENODEV);
//如果得到phy id的话,则create 这个device
return phy_device_create(bus, addr, phy_id, is_c45, &c45_ids);
}
static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id,
bool is_c45, struct phy_c45_device_ids *c45_ids)
{
int phy_reg;
if (is_c45)
return get_phy_c45_ids(bus, addr, phy_id, c45_ids);
/* Grab the bits from PHYIR1, and put them in the upper half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
if (phy_reg < 0)
return -EIO;
*phy_id = (phy_reg & 0xffff) << 16;
/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
if (phy_reg < 0)
return -EIO;
*phy_id |= (phy_reg & 0xffff);
return 0;
}
从get_phy_id 中可以看到phy_id 是由两个16为的MII_PHYSID1和MII_PHYSID2 组合起来的。都是通过mdiobus_read来读取的
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{
int retval;
BUG_ON(in_interrupt());
mutex_lock(&bus->mdio_lock);
retval = bus->read(bus, addr, regnum);
mutex_unlock(&bus->mdio_lock);
return retval;
}
mdiobus_read中就直接调用bus->read
而这里的mii_bus *bus的read一般是mdio driver中实现
例如:
static int hns_mdio_probe(struct platform_device *pdev)
{
struct hns_mdio_device *mdio_dev;
struct mii_bus *new_bus;
struct resource *res;
int ret = -ENODEV;
if (!pdev) {
dev_err(NULL, "pdev is NULL!\r\n");
return -ENODEV;
}
mdio_dev = devm_kzalloc(&pdev->dev, sizeof(*mdio_dev), GFP_KERNEL);
if (!mdio_dev)
return -ENOMEM;
new_bus = devm_mdiobus_alloc(&pdev->dev);
if (!new_bus) {
dev_err(&pdev->dev, "mdiobus_alloc fail!\n");
return -ENOMEM;
}
new_bus->name = MDIO_BUS_NAME;
new_bus->read = hns_mdio_read;
new_bus->write = hns_mdio_write;
new_bus->reset = hns_mdio_reset;
new_bus->priv = mdio_dev;
new_bus->parent = &pdev->dev;
}
回到get_phy_device 中通过mdio driver得到phy id后,就通过phy_device_create 来create 这个设备
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
bool is_c45,
struct phy_c45_device_ids *c45_ids)
{
struct phy_device *dev;
struct mdio_device *mdiodev;
//申请phy_device *dev
/* We allocate the device, and initialize the default values */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
//dev->mdio的赋值
mdiodev = &dev->mdio;
mdiodev->dev.release = phy_device_release;
mdiodev->dev.parent = &bus->dev;
mdiodev->dev.bus = &mdio_bus_type;
mdiodev->bus = bus;
mdiodev->pm_ops = MDIO_BUS_PHY_PM_OPS;
mdiodev->bus_match = phy_bus_match;
mdiodev->addr = addr;
mdiodev->flags = MDIO_DEVICE_FLAG_PHY;
mdiodev->device_free = phy_mdio_device_free;
mdiodev->device_remove = phy_mdio_device_remove;
// 要求上层insmod 这个driver对应的ko
request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
//初始化这个mdiodev->dev
device_initialize(&mdiodev->dev);
return dev;
}
最后回到最前面,当成功创建phy对应的device后调用phy_device_register 注册device
int phy_device_register(struct phy_device *phydev)
{
int err;
err = mdiobus_register_device(&phydev->mdio);
if (err)
return err;
/* 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;
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;
}
phy_device_register 主要是把phy device注册到MDIO bus没,这样就会调用phy driver的probe函数了