Linux内核(八) PHY状态机以及网络相关操作命令解析
生活随笔
收集整理的這篇文章主要介紹了
Linux内核(八) PHY状态机以及网络相关操作命令解析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 背景
- 解析狀態機
- 網絡操作命令解析
- (1)運行ifconfig eth0 up命令
背景
上一篇介紹了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);總結
以上是生活随笔為你收集整理的Linux内核(八) PHY状态机以及网络相关操作命令解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (数学建模)6.1灰色系统理论与灰色关联
- 下一篇: 数据结构-链表结构