IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> [ Linux ] PHY状态机以及网络相关操作命令解析 |CSDN创作打卡 -> 正文阅读

[系统运维][ Linux ] PHY状态机以及网络相关操作命令解析 |CSDN创作打卡

背景

上一篇介绍了PHY设备的识别,构建phy_device结构体的同时,将PHY状态机放在延时队列里,实时更新PHY的状态。介绍文件系统调用命令来对网口进行操作涉及驱动流程。

解析状态机

// drivers/net/phy/phy.c 
// 注册phy_device后,状态机就开始启动,监测phy状态
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;
    int err = 0;

    mutex_lock(&phydev->lock);

    if (phydev->drv->link_change_notify)
        phydev->drv->link_change_notify(phydev);

    switch (phydev->state) {
    case PHY_DOWN:                            // 关闭((ifconfig eth0 down)  
    case PHY_STARTING:                        // 开始  
    case PHY_READY:                           // 准备好  
    case PHY_PENDING:                         // 挂起  
        break;
    case PHY_UP:                              // 开启(ifconfig eth0 up)  
        needs_aneg = true;

        phydev->link_timeout = PHY_AN_TIMEOUT;

        break;
    case PHY_AN:                              // 判断连接状态中 negotiating  
        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:                                   // 开启 未连接  
        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
         */
        if (!phy_interrupt_is_valid(phydev))
            phydev->state = PHY_CHANGELINK;
        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)   // 需要自动配置(例如ifconfig eth0 up就会调用)  
        err = phy_start_aneg(phydev);    // 开始自动配置  
    else if (do_suspend)
        phy_suspend(phydev);

    if (err < 0)
        phy_error(phydev);

    queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
               PHY_STATE_TIME * HZ);
}

网络操作命令解析

(1)运行ifconfig eth0 up命令

// 文件系统输入ifconfig eth0 up
// 状态机切换phy_Up并启动自动配置
case PHY_UP:                         // 开启(ifconfig eth0 up)  
    needs_aneg = true;
    phydev->link_timeout = PHY_AN_TIMEOUT;
    break;
    
if (needs_aneg)   // 需要自动配置(例如ifconfig eth0 up就会调用)  
   err = phy_start_aneg(phydev);    // 开始自动配置 
// 1、调用驱动的配置函数(没有特殊的phy芯片配置,就调用通用的配置)
// 2、调整phy当前的状态
int phy_start_aneg(struct phy_device *phydev)
{
    int err;

    mutex_lock(&phydev->lock);

    if (AUTONEG_DISABLE == phydev->autoneg)
        phy_sanitize_settings(phydev);

    /* Invalidate LP advertising flags */
    phydev->lp_advertising = 0;

    err = phydev->drv->config_aneg(phydev);    // 调用驱动的config_aneg方法,默认是genphy_config_aneg  
    if (err < 0)
        goto out_unlock;

    if (phydev->state != PHY_HALTED) {          // 调整修改PHY设备状态  
        if (AUTONEG_ENABLE == phydev->autoneg) {
            phydev->state = PHY_AN;
            phydev->link_timeout = PHY_AN_TIMEOUT;
        } else {
            phydev->state = PHY_FORCING;
            phydev->link_timeout = PHY_FORCE_TIMEOUT;
        }
    }

out_unlock:
    mutex_unlock(&phydev->lock);
    return err;
}
EXPORT_SYMBOL(phy_start_aneg);
// drivers/net/phy/phy_device.c
int genphy_config_aneg(struct phy_device *phydev)
{
    int result;

    if (AUTONEG_ENABLE != phydev->autoneg)
        return genphy_setup_forced(phydev);

    result = genphy_config_advert(phydev);
    if (result < 0) /* error */
        return result;
    if (result == 0) {
        /* Advertisement hasn't changed, but maybe aneg was never on to
         * begin with?  Or maybe phy was isolated?
         */
        int ctl = phy_read(phydev, MII_BMCR);      // 获取状态  

        if (ctl < 0)
            return ctl;

        if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
            result = 1; /* do restart aneg */
    }

    /* Only restart aneg if we are advertising something different
     * than we were before.
     */
    if (result > 0)
        result = genphy_restart_aneg(phydev);    // 重新开启自动协商机制  

    return result;
}
EXPORT_SYMBOL(genphy_config_aneg);
// drivers/net/phy/phy_device.c
int genphy_restart_aneg(struct phy_device *phydev)
{
    int ctl = phy_read(phydev, MII_BMCR);          // 获取基本状态  

    if (ctl < 0)
        return ctl;

    ctl |= BMCR_ANENABLE | BMCR_ANRESTART;   // 使能自动协商机制及支援重启

    /* Don't isolate the PHY if we're negotiating */
    ctl &= ~BMCR_ISOLATE;

    return phy_write(phydev, MII_BMCR, ctl);     // 写命令  
}
EXPORT_SYMBOL(genphy_restart_aneg);
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-01-12 00:27:51  更:2022-01-12 00:28:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 6:33:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码