PHY的12种状态

enum phy_state {
PHY_DOWN = 0, //关闭网卡
PHY_STARTING, //PHY设备准备好了,PHY driver尚为准备好
PHY_READY, //PHY设备注册成功
PHY_PENDING, //PHY芯片挂起
PHY_UP, //开启网卡
PHY_AN, //网卡自协商
PHY_RUNNING, //网卡已经插入网线并建立物理连接,该状态可切换到PHY_CHANGELINK
PHY_NOLINK, //断网,拔掉网线
PHY_FORCING,//自动协商失败,强制处理(读phy状态寄存器,设置速率,设置工作模式)
PHY_CHANGELINK, //LINK检查,当物理连接存在时切换到PHY_RUNING,物理连接不存在时切换到PHY_NOLINK
PHY_HALTED, //网卡关闭时,PHY挂起
PHY_RESUMING //网卡开启时,PHY恢复
};

PHY状态机



PHY指PHY芯片,负责数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。

MAC指MAC芯片,属于数据链路层,提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。

PHY_DOWN: phy、phy driver、mac都没准备好

  1. 如果phy driver被集成在内核中,PHY.probe后,phydev状态为PHY_READY。
  2. 如果phy driver被未集成在内核中,PHY.probe后,phydev状态为PHY_STARTING。

PHY_READY:phy、phy driver已经就绪,mac未准备好

当MAC层加载时,在PHY.start后,phydev状态切换为PHY_UP。

PHY_STARTING:phy准备就绪,phy driver、mac未准备好

  1. 当MAC加载时,PHY.start后,phydev状态为PHY_PENDING。
  2. 当phy driver加载时,phydev状态为PHY_READY。

PHY_PENDING:phy、mac准备就绪,phy driver未准备好

当phy dirver加载后,phdev状态为PHY_UP

上图中0-->1-->2-->4、0-->2-->4代表phy、phy dirver、mac顺序加载。

0-->1-->3-->4代表phy、mac、phy driver顺序加载。

PHY_UP:phy、phy driver、mac准备就绪

当前状态将启动自动协商,若启动成功则进入PHY_AN,若启动失败则进入PHY_FORCING。

PHY_AN:网卡自协商模式,检测自协商是否完成。

先判断物理链路的状态,如果未LINK则进入PHY_NOLINK,如果LINK则判断自协商是否完成,

自协商完成进入PHY_RUNNING,若自协商超时则重新开启自协商。

PHY_FORCING:强制协商

读link和自协商状态寄存器,如果状态正常则进入PHY_RUNNING模式。

PHY_NOLINK:物理链路未连接

判断物理链路状态,如果LINK,再判断是否支持自协商,若支持待自协商完成后进入PHY_RUNNING模式,

若不支持,直接进入PHY_RUNNING模式。若自协商处于挂起状态,则进入PHY_AN模式。

PHY_RUNNING:正常运行中

获取当前link状态,当link状态发生改变时,进入PHY_CHANGELINK模式。

PHY_CHANGELINK:检查物理链路

物理链路link时,切换到PHY_RUNNING,非LINK时切换到PHY_NOLINK。

PHY_HALTED:网卡关闭phy_stop

挂起phy

PHY_RESUMING: 网卡启用phy_start

恢复phy

phy_state_machine是PHY的状态机函数

/**
* phy_state_machine - Handle the state machine
* @work: work_struct that describes the work to be done
*/
void phy_state_machine(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
container_of(dwork, struct phy_device, state_queue);
bool needs_aneg = false, do_suspend = false;
enum phy_state old_state;
int err = 0;
int old_link; mutex_lock(&phydev->lock); old_state = phydev->state; if (phydev->drv->link_change_notify)
phydev->drv->link_change_notify(phydev); switch (phydev->state) {
case PHY_DOWN:
case PHY_STARTING:
case PHY_READY:
case PHY_PENDING:
break;
case PHY_UP:
needs_aneg = true; phydev->link_timeout = PHY_AN_TIMEOUT; break;
case PHY_AN:
err = phy_read_status(phydev);
if (err < 0)
break; /* If the link is down, give up on negotiation for now */
if (!phydev->link) {
phydev->state = PHY_NOLINK;
netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
break;
} /* Check if negotiation is done. Break if there's an error */
err = phy_aneg_done(phydev);
if (err < 0)
break; /* If AN is done, we're running */
if (err > 0) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev); } else if (0 == phydev->link_timeout--)
needs_aneg = true;
break;
case PHY_NOLINK:
if (phy_interrupt_is_valid(phydev))
break; err = phy_read_status(phydev);
if (err)
break; if (phydev->link) {
if (AUTONEG_ENABLE == phydev->autoneg) {
err = phy_aneg_done(phydev);
if (err < 0)
break; if (!err) {
phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT;
break;
}
}
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
}
break;
case PHY_FORCING:
err = genphy_update_link(phydev);
if (err)
break; if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
if (0 == phydev->link_timeout--)
needs_aneg = true;
} phydev->adjust_link(phydev->attached_dev);
break;
case PHY_RUNNING:
/* Only register a CHANGE if we are polling or ignoring
* interrupts and link changed since latest checking.
*/
if (!phy_interrupt_is_valid(phydev)) {
old_link = phydev->link;
err = phy_read_status(phydev);
if (err)
break; if (old_link != phydev->link)
phydev->state = PHY_CHANGELINK;
}
/*
* Failsafe: check that nobody set phydev->link=0 between two
* poll cycles, otherwise we won't leave RUNNING state as long
* as link remains down.
*/
if (!phydev->link && phydev->state == PHY_RUNNING) {
phydev->state = PHY_CHANGELINK;
dev_err(&phydev->dev, "no link in PHY_RUNNING\n");
}
break;
case PHY_CHANGELINK:
err = phy_read_status(phydev);
if (err)
break; if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
netif_carrier_off(phydev->attached_dev);
} phydev->adjust_link(phydev->attached_dev); if (phy_interrupt_is_valid(phydev))
err = phy_config_interrupt(phydev,
PHY_INTERRUPT_ENABLED);
break;
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
do_suspend = true;
}
break;
case PHY_RESUMING:
if (AUTONEG_ENABLE == phydev->autoneg) {
err = phy_aneg_done(phydev);
if (err < 0)
break; /* err > 0 if AN is done.
* Otherwise, it's 0, and we're still waiting for AN
*/
if (err > 0) {
err = phy_read_status(phydev);
if (err)
break; if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
}
phydev->adjust_link(phydev->attached_dev);
} else {
phydev->state = PHY_AN;
phydev->link_timeout = PHY_AN_TIMEOUT;
}
} else {
err = phy_read_status(phydev);
if (err)
break; if (phydev->link) {
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
}
phydev->adjust_link(phydev->attached_dev);
}
break;
} mutex_unlock(&phydev->lock); if (needs_aneg)
err = phy_start_aneg(phydev);
else if (do_suspend)
phy_suspend(phydev); if (err < 0)
phy_error(phydev); dev_dbg(&phydev->dev, "PHY state change %s -> %s\n",
phy_state_to_str(old_state), phy_state_to_str(phydev->state)); queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
PHY_STATE_TIME * HZ);
}

最新文章

  1. (转)Singleton 单例模式(懒汉方式和饿汉方式)
  2. 今天遇到的关于mysql的max_allowed_packet的问题
  3. Git基本命令(一)
  4. SVN Unable to connect to a repository at URL
  5. windows XP系统内核文件分析(全)
  6. Jetty学习(一)
  7. Java基础中的一些注意点(续)
  8. hdu 4763 &amp;&amp; 2013 ACM/ICPC 长春网络赛解题报告
  9. at命令
  10. 关于jquery对象和DOM对象的区别
  11. Virtual Box虚拟机Ubuntu系统安装及基本配置
  12. SQLserver登陆报错
  13. 关于pycharm中使用charts无法显示图表的问题(属于个人粗心问题)
  14. wchar_t和char转化
  15. Python之路3【知识点】白话Python编码和文件操作(截载)
  16. 为什么redis支持lua脚本功能
  17. vue-Treeselect实现组织机构(员工)下拉树的功能
  18. MyBatis基本工作原理
  19. 替换国内yum源以及pip源
  20. maven工程下testng简单使用

热门文章

  1. PGL图学习之项目实践(UniMP算法实现论文节点分类、新冠疫苗项目实战,助力疫情)[系列九]
  2. 【企业流行新数仓】Day01:新版本对比、业务和表的介绍☆、Hive、ODS层、DWD层
  3. 12V转5V降压芯片,12V转3.3V稳压芯片电路图
  4. 如何搭建自己的CICD流水线,实现自动编译部署功能?
  5. 为什么总是应该考虑给定 List 的初始大小
  6. Jenkins&amp;&amp;gitlab2
  7. asp前端无法获取后端中select *查询带出来的全部字段
  8. [机器学习] PCA (主成分分析)详解
  9. Kaliの一些网络操作
  10. [Leetcode] 寻找数组的中心索引