翼度科技»论坛 云主机 LINUX 查看内容

PHY状态机分析

4

主题

4

帖子

12

积分

新手上路

Rank: 1

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


PHY指PHY芯片,负责数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。
MAC指MAC芯片,属于数据链路层,提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。
PHY_DOWN: phy、phy driver、mac都没准备好

  • 如果phy driver被集成在内核中,PHY.probe后,phydev状态为PHY_READY。
  • 如果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未准备好

  • 当MAC加载时,PHY.start后,phydev状态为PHY_PENDING。
  • 当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的状态机函数
  1. /**
  2. * phy_state_machine - Handle the state machine
  3. * @work: work_struct that describes the work to be done
  4. */
  5. void phy_state_machine(struct work_struct *work)
  6. {
  7.         struct delayed_work *dwork = to_delayed_work(work);
  8.         struct phy_device *phydev =
  9.                         container_of(dwork, struct phy_device, state_queue);
  10.         bool needs_aneg = false, do_suspend = false;
  11.         enum phy_state old_state;
  12.         int err = 0;
  13.         int old_link;
  14.         mutex_lock(&phydev->lock);
  15.         old_state = phydev->state;
  16.         if (phydev->drv->link_change_notify)
  17.                 phydev->drv->link_change_notify(phydev);
  18.         switch (phydev->state) {
  19.         case PHY_DOWN:
  20.         case PHY_STARTING:
  21.         case PHY_READY:
  22.         case PHY_PENDING:
  23.                 break;
  24.         case PHY_UP:
  25.                 needs_aneg = true;
  26.                 phydev->link_timeout = PHY_AN_TIMEOUT;
  27.                 break;
  28.         case PHY_AN:
  29.                 err = phy_read_status(phydev);
  30.                 if (err < 0)
  31.                         break;
  32.                 /* If the link is down, give up on negotiation for now */
  33.                 if (!phydev->link) {
  34.                         phydev->state = PHY_NOLINK;
  35.                         netif_carrier_off(phydev->attached_dev);
  36.                         phydev->adjust_link(phydev->attached_dev);
  37.                         break;
  38.                 }
  39.                 /* Check if negotiation is done.  Break if there's an error */
  40.                 err = phy_aneg_done(phydev);
  41.                 if (err < 0)
  42.                         break;
  43.                 /* If AN is done, we're running */
  44.                 if (err > 0) {
  45.                         phydev->state = PHY_RUNNING;
  46.                         netif_carrier_on(phydev->attached_dev);
  47.                         phydev->adjust_link(phydev->attached_dev);
  48.                 } else if (0 == phydev->link_timeout--)
  49.                         needs_aneg = true;
  50.                 break;
  51.         case PHY_NOLINK:
  52.                 if (phy_interrupt_is_valid(phydev))
  53.                         break;
  54.                 err = phy_read_status(phydev);
  55.                 if (err)
  56.                         break;
  57.                 if (phydev->link) {
  58.                         if (AUTONEG_ENABLE == phydev->autoneg) {
  59.                                 err = phy_aneg_done(phydev);
  60.                                 if (err < 0)
  61.                                         break;
  62.                                 if (!err) {
  63.                                         phydev->state = PHY_AN;
  64.                                         phydev->link_timeout = PHY_AN_TIMEOUT;
  65.                                         break;
  66.                                 }
  67.                         }
  68.                         phydev->state = PHY_RUNNING;
  69.                         netif_carrier_on(phydev->attached_dev);
  70.                         phydev->adjust_link(phydev->attached_dev);
  71.                 }
  72.                 break;
  73.         case PHY_FORCING:
  74.                 err = genphy_update_link(phydev);
  75.                 if (err)
  76.                         break;
  77.                 if (phydev->link) {
  78.                         phydev->state = PHY_RUNNING;
  79.                         netif_carrier_on(phydev->attached_dev);
  80.                 } else {
  81.                         if (0 == phydev->link_timeout--)
  82.                                 needs_aneg = true;
  83.                 }
  84.                 phydev->adjust_link(phydev->attached_dev);
  85.                 break;
  86.         case PHY_RUNNING:
  87.                 /* Only register a CHANGE if we are polling or ignoring
  88.                  * interrupts and link changed since latest checking.
  89.                  */
  90.                 if (!phy_interrupt_is_valid(phydev)) {
  91.                         old_link = phydev->link;
  92.                         err = phy_read_status(phydev);
  93.                         if (err)
  94.                                 break;
  95.                         if (old_link != phydev->link)
  96.                                 phydev->state = PHY_CHANGELINK;
  97.                 }
  98.                 /*
  99.                  * Failsafe: check that nobody set phydev->link=0 between two
  100.                  * poll cycles, otherwise we won't leave RUNNING state as long
  101.                  * as link remains down.
  102.                  */
  103.                 if (!phydev->link && phydev->state == PHY_RUNNING) {
  104.                         phydev->state = PHY_CHANGELINK;
  105.                         dev_err(&phydev->dev, "no link in PHY_RUNNING\n");
  106.                 }
  107.                 break;
  108.         case PHY_CHANGELINK:
  109.                 err = phy_read_status(phydev);
  110.                 if (err)
  111.                         break;
  112.                 if (phydev->link) {
  113.                         phydev->state = PHY_RUNNING;
  114.                         netif_carrier_on(phydev->attached_dev);
  115.                 } else {
  116.                         phydev->state = PHY_NOLINK;
  117.                         netif_carrier_off(phydev->attached_dev);
  118.                 }
  119.                 phydev->adjust_link(phydev->attached_dev);
  120.                 if (phy_interrupt_is_valid(phydev))
  121.                         err = phy_config_interrupt(phydev,
  122.                                                    PHY_INTERRUPT_ENABLED);
  123.                 break;
  124.         case PHY_HALTED:
  125.                 if (phydev->link) {
  126.                         phydev->link = 0;
  127.                         netif_carrier_off(phydev->attached_dev);
  128.                         phydev->adjust_link(phydev->attached_dev);
  129.                         do_suspend = true;
  130.                 }
  131.                 break;
  132.         case PHY_RESUMING:
  133.                 if (AUTONEG_ENABLE == phydev->autoneg) {
  134.                         err = phy_aneg_done(phydev);
  135.                         if (err < 0)
  136.                                 break;
  137.                         /* err > 0 if AN is done.
  138.                          * Otherwise, it's 0, and we're  still waiting for AN
  139.                          */
  140.                         if (err > 0) {
  141.                                 err = phy_read_status(phydev);
  142.                                 if (err)
  143.                                         break;
  144.                                 if (phydev->link) {
  145.                                         phydev->state = PHY_RUNNING;
  146.                                         netif_carrier_on(phydev->attached_dev);
  147.                                 } else        {
  148.                                         phydev->state = PHY_NOLINK;
  149.                                 }
  150.                                 phydev->adjust_link(phydev->attached_dev);
  151.                         } else {
  152.                                 phydev->state = PHY_AN;
  153.                                 phydev->link_timeout = PHY_AN_TIMEOUT;
  154.                         }
  155.                 } else {
  156.                         err = phy_read_status(phydev);
  157.                         if (err)
  158.                                 break;
  159.                         if (phydev->link) {
  160.                                 phydev->state = PHY_RUNNING;
  161.                                 netif_carrier_on(phydev->attached_dev);
  162.                         } else        {
  163.                                 phydev->state = PHY_NOLINK;
  164.                         }
  165.                         phydev->adjust_link(phydev->attached_dev);
  166.                 }
  167.                 break;
  168.         }
  169.         mutex_unlock(&phydev->lock);
  170.         if (needs_aneg)
  171.                 err = phy_start_aneg(phydev);
  172.         else if (do_suspend)
  173.                 phy_suspend(phydev);
  174.         if (err < 0)
  175.                 phy_error(phydev);
  176.         dev_dbg(&phydev->dev, "PHY state change %s -> %s\n",
  177.                 phy_state_to_str(old_state), phy_state_to_str(phydev->state));
  178.         queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
  179.                            PHY_STATE_TIME * HZ);
  180. }
复制代码
来源:https://www.cnblogs.com/forwards/p/17101019.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具