PHY狀態機分析

来源:https://www.cnblogs.com/forwards/archive/2023/02/08/17101019.html
-Advertisement-
Play Games

PHY的12種狀態 enum phy_state { PHY_DOWN = 0, //關閉網卡 PHY_STARTING, //PHY設備準備好了,PHY driver尚為準備好 PHY_READY, //PHY設備註冊成功 PHY_PENDING, //PHY晶元掛起 PHY_UP, //開啟網卡 ...


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指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);
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 隨著技術的進步,跨平臺開發已經成為了標配,在此大背景下,ASP.NET Core也應運而生。本文主要基於ASP.NET Core+Element+Sql Server開發一個校園圖書管理系統為例,簡述基於MVC三層架構開發的常見知識點,前三篇篇文章簡單介紹瞭如何搭建開發框架,登錄功能,主頁面功能,以... ...
  • WPF框架代碼很龐雜不容易學習,這裡記錄我自己學習的點點滴滴。以wpf-4.8.0-rc1.19455.14為探索對象,相關代碼可在WPF倉庫下載。代碼結構大致如下: PresentationFramework 是最頂層抽象介面,開發中用到的大部分類都來源於此,包含各個控制項,圖形,動畫,綁定,XAM ...
  • 概述 開放封閉原則是面向對象所有原則的核心。對功能擴展開放,面向修改代碼封閉。 需求改變時,在小改變軟體實體源代碼(類、介面、方法等)的前提下通過擴展功能使其滿足新的需求。 需求 描述不同需求的用戶去銀行辦理不同的業務 分析需求 1、在這段程式中 會有多少個對象2、每個對象的屬性和行為對象1: 用戶 ...
  • docker問題 1. 安裝 docker 下載依賴環境 yum -y install yum-utils device-mapper-persistent-data lvm2 指定Docker鏡像源 # 使用的是阿裡的 yum-config-manager --add-repo http://mi ...
  • 一鍵部署nfs、rsync、sersync 項目代碼: 鏈接:https://pan.baidu.com/s/13I0BBAYsdK-KmPekZ5VpdA 提取碼:u2tw --來自百度網盤超級會員V6的分享 目錄結構 [root@m01 /ansible/roles]# tree -F . ├─ ...
  • Windows server 共用的文件操作日誌預設是沒有打開的,需要手動打開,本篇文章將詳細說明如何打開。並且如何將這個日誌輸出到ELK日誌系統中。 手動打開操作日誌 1、打開你的共用審核功能 舉例:我需要監控D盤的文件讀取、寫入、刪除等操作 右鍵D盤屬性 安全 高級 審核 繼續 添加需要監視的用 ...
  • GMAC網卡相關介紹與分析 環境描述 MII 本節信息來源 MII MII共16根線,數據位寬4(tx rx各4根信號線),TX_CLK RX_CLK均是PHY提供的。 TX_ER(Transmit Error): 發送數據錯誤提示信號,同步於TX_CLK,高電平有效,表示TX_ER有效期內傳輸的數 ...
  • M1晶元 VMware安裝centOS 1.安裝 VMware VMware個人免費,可以直接在官網下載 官網地址:https://www.vmware.com/cn.html 2.安裝 1.下載鏡像 !!!這裡是一個大坑,從官網下載的鏡像,沒辦法使用,我下載了五六個arm鏡像,全是卡在安裝界面,一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...