三 Linux 网络驱动-MAC、PHY层驱动框架( 六 )


继续回到示例代码 ,接着分析函数 。
第 173 行 , 先调用函数通知内核 , 先关闭链路 ,  会打开
第 174 行 , 调用函数使能网络相关时钟 。
第 177 行 , 调用函数注册 !
2、MDIO 总线注册
MDIO 我们讲了很多次了 , 就是用来管理 PHY 芯片的 , 分为 MDIO 和 MDC 两根线 , Linux 内核专门为 MDIO 准备一个总线 , 叫做 MDIO 总线 , 采用结构体表示 , 定义在 /linux/phy.h 文件中 ,  结构体如下所示:
1 struct mii_bus {2const char *name;3char id[MII_BUS_ID_SIZE];4void *priv;5int (*read)(struct mii_bus *bus, int phy_id, int regnum);6int (*write)(struct mii_bus *bus, int phy_id, int regnum,u16 val);7int (*reset)(struct mii_bus *bus);8 9/*10* A lock to ensure that only one thing can read/write11* the MDIO bus at a time12*/13struct mutex mdio_lock;1415struct device *parent;16enum {17MDIOBUS_ALLOCATED = 1,18MDIOBUS_REGISTERED,19MDIOBUS_UNREGISTERED,20MDIOBUS_RELEASED,21} state;22struct device dev;2324/* list of all PHYs on bus */25struct phy_device *phy_map[PHY_MAX_ADDR];2627/* PHY addresses to be ignored when probing */28u32 phy_mask;2930/*31* Pointer to an array of interrupts, each PHY's32* interrupt at the index matching its address33*/34int *irq;35 };
重点是第 5、6 两行的 read 和 write 函数 , 这两个函数就是读/些 PHY 芯片的操作函数 , 不 同的 SOC 其 MDIO 主控部分是不一样的 , 因此需要驱动编写人员去编写 。我们前面在分析函数的时候已经讲过了 ,  函数会调用函数完成 MII 接口的 初始化 , 其中就包括初始化下的 read 和 write 这两个函数 。最终通过或者函数将初始化以后的注册到 Linux 内核 ,  函 数其实最终也是调用的函数来完成注册的 。函数 内容如下(限于篇幅 , 有省略):
示例代码of_mdiobus_register 函数1 int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)2 {3struct device_node *child;4const __be32 *paddr;5bool scanphys = false;6int addr, rc, i;7 8/* Mask out all PHYs from auto probing. Instead the PHYs listed 9* in the device tree are populated after the bus has been *registered */10mdio->phy_mask = ~0;1112/* Clear all the IRQ properties */13if (mdio->irq)14for (i=0; iirq[i] = PHY_POLL;1617mdio->dev.of_node = np;1819/* Register the MDIO bus */20rc = mdiobus_register(mdio);21if (rc)22return rc;2324/* Loop over the child nodes and register a phy_device for each one*/25for_each_available_child_of_node(np, child) {26addr = of_mdio_parse_addr(&mdio->dev, child);27if (addr < 0) {28scanphys = true;29continue;30}3132rc = of_mdiobus_register_phy(mdio, child, addr);33if (rc)34continue;35}3637if (!scanphys)38return 0;39 ......62return 0;63 }
第 20 行 , 调用函数来向 Linux 内核注册 mdio 总线!
第 25 行 , 轮询 mdio 节点下的所有子节点 , 比如示例代码 69.4.1.2 中的“: -phy@0”和“: -phy@1”这两个子节点 , 这两个子节点描述的是 PHY 芯片信息 。
第 26 行 , 提取设备树子节点中 PHY 地址 , 也就是 : -phy@0”和“: -phy@1”这两个子节点对应的 PHY 芯片地址 , 分别为 0 和 1 。
第 32 行 , 调用 phy 函数向 Linux 内核注册 phy 。
简单总结一下 ,  函数有两个主要的功能 , 一个是通过函数向 Linux 内核注册 mdio 总线 , 另一个就是通过 phy 函数向内核注册 PHY 。
接下来简单分析一下 phy 函数 , 看看是如何向 Linux 内核注册 PHY 设 备的 , phy 函数内容如下所示: