问题: PHY 是怎么启动的
当执行ifconfig eth0 up 希望启动网络的时候,会执行 网卡设备的操作集 open()
struct net_device
const struct net_device_ops *netdev_ops; = &stmmac_netdev_ops-------+
|
|
static const struct net_device_ops stmmac_netdev_ops = {----------------+
.ndo_open = stmmac_open,
...
};
stmmac_open()会去尝试到mdio总线上 匹配 phy device 与 phy driver 。 当匹配成功后 会调用 phy driver的 probe()函数,设置 phy 状态为准备状态PHY_READY,启动phy 状态机任务phy_state_machine 函数。然后做一系列操作后 最终 切换phy 状态为驱动 PHY_UP,这样 状态机任务就会继续执行下去。该函数一直在运行(每隔一秒检测一次网络状态),判断不同的网络状态作出不同的动作。其中CHANGELINK是会根据网络连、断来判断是RUNNING还是NOLINK。这样,就知道网络是连接上还是断开。
关于PHY 状态机的状态切换
enum phy_state {
PHY_DOWN = 0,//PHY 没准备好
PHY_STARTING,//PHY 芯片OK了
PHY_READY,//准备好了,会在phy driver probe()中切换状态机状态到 PHY_UP
PHY_PENDING,
PHY_UP, //PHY 启动
PHY_AN, //自动协商
PHY_RUNNING, //正在运行
PHY_NOLINK, //断网
PHY_FORCING,
PHY_CHANGELINK, //状态变化
PHY_HALTED,
PHY_RESUMING
};
phy状态变化主要在 phy_state_machine 函数。该函数一直在运行(每隔一秒检测一次网络状态),该函数判断不同的网络状态作出不同的动作。其中CHANGELINK是会根据网络连、断来判断是RUNNING还是NOLINK。这样,就知道网络是连接上还是断开
rivers\net\ethernet\stmicro\stmmac\stmmac_main.c
static int stmmac_open(struct net_device *dev)
{
...
/*
目前分析的工作:
如
1 到 mdio 总线上查找目标 phy 设备
2 匹配到对应 phy driver 后 调用 phy driver 的probe(),设置phy 状态为 "准备好了"
3 启动phy 状态机任务
*/
ret = stmmac_init_phy(dev);
if (ret) {
netdev_err(priv->dev,
"%s: Cannot attach to PHY (error: %d)\n",
__func__, ret);
return ret;
}
...
//分配TX/RX资源
ret = alloc_dma_desc_resources(priv);
//初始化RX/TX的回环描述
ret = init_dma_desc_rings(dev, GFP_KERNEL);
//检查MAC 地址
stmmac_check_ether_addr(priv);
//设置mac为可用状态,配置mac核心寄存器,然后DMA数据准备接收和发送
ret = stmmac_hw_setup(dev, true);
...
//启动PHY设备
// PHY 状态切换: PHY_READY---->PHY_UP
phy_start(dev->phydev);
...
}
/**
* stmmac_init_phy - PHY initialization PHY初始化
* @dev: net device structure
工作:
如 到mdio 总线上查找 目标phy device,当
*/
static int stmmac_init_phy(struct net_device *dev)
{
//获取网卡设备的 私有数据
struct stmmac_priv *priv = netdev_priv(dev);
...
/* 在 GMAC控制器初始化的时候,已经解析了 phy配置节点
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
struct device_node *phy_node; //phy配置节点
*/
if (priv->plat->phy_node) {
/*
struct net_device *dev
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
struct device_node *phy_node; //phy配置节点
void stmmac_adjust_link(struct net_device *dev)
0
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
int interface;
*/
phydev = of_phy_connect(dev, priv->plat->phy_node,&stmmac_adjust_link, 0, interface);
}
...
}
drivers\of\of_mdio.c
/** 连接到设备树中描述的phy
* of_phy_connect - Connect to the phy described in the device tree
目前分析的工作:
如
1 到 mdio 总线上查找目标 phy 设备
2 匹配到对应 phy driver 后 调用 phy driver 的probe(),设置phy 状态为 "准备好了"
3 启动phy 状态机任务
*/
/*
struct net_device *dev
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
struct device_node *phy_node; //phy配置节点
void stmmac_adjust_link(struct net_device *dev)
0
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
int interface;
*/
struct phy_device *of_phy_connect(struct net_device *dev,
struct device_node *phy_np,
void (*hndlr)(struct net_device *), u32 flags,
phy_interface_t iface)
{
/* 到 mdio 总线上查找目标 phy 设备
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
struct device_node *phy_node; //phy配置节点
*/
struct phy_device *phy = of_phy_find_device(phy_np);
int ret;
if (!phy)
return NULL;
phy->dev_flags = flags;
/*
struct net_device *dev
目标 phy 设备 struct phy_device
void stmmac_adjust_link(struct net_device *dev)
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
int interface = PHY_INTERFACE_MODE_RMII;
*/
ret = phy_connect_direct(dev, phy, hndlr, iface);
/* refcount is held by phy_connect_direct() on success */
put_device(&phy->mdio.dev);
return ret ? NULL : phy;
}
EXPORT_SYMBOL(of_phy_connect);
/**
* of_phy_find_device - Give a PHY node, find the phy_device
* @phy_np: Pointer to the phy's device tree node
/*
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
struct device_node *phy_node; //phy配置节点
*/
struct phy_device *of_phy_find_device(struct device_node *phy_np)
{
struct device *d;
struct mdio_device *mdiodev;
if (!phy_np)
return NULL;
/*
在 GMAC 控制器初始化注册的时候,检索并创建了mdio总线上的 phy 设备,并注册了phy设备到 mdio_bus 总线
所以这里 可以获取到目标 phy_device
*/
d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
if (d) {
/*
struct phy_device
struct mdio_device mdio
struct device dev;
*/
mdiodev = to_mdio_device(d);
if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY){
//获取 struct phy_device
return to_phy_device(d);
}
put_device(d);
}
return NULL;
}
EXPORT_SYMBOL(of_phy_find_device);
/**
* phy_connect_direct - connect an ethernet device to a specific phy_device
* @dev: the network device to connect
* @phydev: the pointer to the phy device
* @handler: callback function for state change notifications
* @interface: PHY device's interface
*/
/*
struct net_device *dev
目标 phy 设备 struct phy_device
void stmmac_adjust_link(struct net_device *dev)
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
int interface = PHY_INTERFACE_MODE_RMII;
*/
int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
void (*handler)(struct net_device *),
phy_interface_t interface)
{
int rc;
if (!dev)
return -EINVAL;
/*
struct net_device *dev
目标 phy 设备 struct phy_device
...
struct net_device{
}+网卡私有数据
struct stmmac_priv
//gmac控制器所有配置信息
struct plat_stmmacenet_data *plat;
int interface = PHY_INTERFACE_MODE_RMII;
工作 :
比如 调用 phy driver 的probe() ,设置phy 状态为 "准备好了"
*/
rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
if (rc)
return rc;
phy_prepare_link(phydev, handler);
// 启动phy 状态机任务
phy_start_machine(phydev);
if (phydev->irq > 0)
phy_start_interrupts(phydev);
return 0;
}
EXPORT_SYMBOL(phy_connect_direct);
/** 将网络设备附加到给定的PHY设备指针
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
* @phydev: Pointer to phy_device to attach
* @flags: PHY device's dev_flags
* @interface: PHY device's interface
*
工作 :
比如 调用 phy driver 的probe() ,设置phy 状态为 "准备好了"
*/
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
/*
struct phy_device
struct mdio_device mdio
struct device dev;
*/
struct device *d = &phydev->mdio.dev;
...
/* 执行 phy driver 的probe()
struct device
// which driver has allocated this device
struct device_driver *driver;
int (*probe) (struct device *dev);
工作:
比如 设置 phy 状态为 "准备好了"
*/
err = d->driver->probe(d);
...
}
drivers\net\phy\phy_device.c
/**
* phy_probe - probe and init a PHY device
* @dev: device to probe and init
*
* Description: Take care of setting up the phy_device structure,
* set the state to READY (the driver's init function should
* set it to STARTING if needed).
*/
static int phy_probe(struct device *dev)
{
struct phy_device *phydev = to_phy_device(dev);
...
/* Set the state to READY by default */
//设置 phy 状态为 "准备好了"
phydev->state = PHY_READY;
...
}
/**
* phy_start_machine - start PHY state machine tracking
* @phydev: the phy_device struct
*/
void phy_start_machine(struct phy_device *phydev)
{
/* 启动phy 状态机任务
在创建 phy 设备的时候 建立了状态机任务
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
*/
queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, HZ);
}
EXPORT_SYMBOL_GPL(phy_start_machine);
412



被折叠的 条评论
为什么被折叠?



