device的關聯(MDIO模塊分析之五)

前面幾章基本上完成了mdio模塊驅動模型的分析,本篇文章主要講述phy device的狀態機以及phy device與net_device的關聯。Phy device主要是對phy的抽象,而net_device主要是對mac的抽象,而mdio總線以及mii_bus主要用於對phy設備的控制(包括設置phy設備的工作模式、速率模式、是否為自適應、phy的link狀態等),而net_device需要根據phy的工作模式、速率模式、phy的link狀態進行狀態的同步,因此需要將net_device與phy device進行綁定與解綁。本章主要分為兩個方面:

一、phy_device與net_device的綁定與解綁

二、phy device的狀態機


一、phy_device與net_device的綁定與解綁操作。

什麼時候實現phy_device與net_device的綁定與解綁操作?

我們從現有各廠家的net_device驅動可以看到,大致存在兩種模式:

  1. 在net_device的probe接口中,根據傳遞的mdio_bus_id、phy_id,查找phy_device並完成net_device與phy_device的關聯;在net_device的remove接口中,完成net_device與phy_device的解綁操作;
  2. 在net_device->netdev_ops->ndo_open接口中,據傳遞的mdio_bus_id、phy_id,查找phy_device並完成net_device與phy_device的關聯;在nnet_device->netdev_ops->ndo_stop中,完成net_device與phy_device的解綁操作(即應用層執行ifconfig xxx up/down操作時調用ndo_open/ndo_stop)。

關於phy_device與net_device的綁定與解綁主要涉及如下幾個函數phy_connect、phy_disconnect下面我們分析下這兩個接口的主要工呢

phy_connect分析

該接口主要用來進行一個net_device類型的變量與phy_device類型的變量的關聯、設置phy_device的狀態為PHY_READY,並啟動phy_device的狀態機,詳細處理流程如下圖所示

  1. 確認phy_device是否存在(根據傳遞的phy_device_id,在mdio_bus_type中查找phy_deviec);
  2. 若phy_device存在,則進行net_device與phy_device的相互關聯(phy_device->attached_dev、net_device->phydev),並調用phy_driver->config_init完成對phy device的初始化;
  3. 啟動phy_device的狀態機對應的延遲隊列。


LINUX PHY狀態機分析及其與net_device的關聯(MDIO模塊分析之五)

phy_disconnect分析

phy_disconnect的操作剛好與phy_connect接口的操作相反,主要提供的功能如下:

  1. 若phy_device支持中斷,則調用phy_stop_interrupts關閉中斷,並free該中斷;
  2. 調用phy_stop_machine接口,關閉該phy_device的狀態機對應的延遲隊列;
  3. 解除net_device與phy_device關聯,若該phy_device是與genphy_driver綁定,則調用device_release_driver解除它們之間的綁定關係。


LINUX PHY狀態機分析及其與net_device的關聯(MDIO模塊分析之五)

phy_device irq相關說明

在上面的介紹中,我們提到了phy_device的中斷,針對phy_device的中斷而言,當兩個phy之間的link up/down的變化後(兩個phy完成速率協商或者連接斷開時),則會觸發該中斷,從而觸發phy_device的狀態機的轉變(狀態轉換至PHY_RUNNING/PHY_NOLINK)。

那若phy_device不支持中斷模式呢?那就使用PHY_POLL模式,在該模式下則當phy_device處於PHY_RUNNING狀態時,則將phy_device狀態自動切換至PHY_CHANGELINK狀態,而在PHY_CHANGELINK狀態下通過對phy_device的狀態寄存器,確定phy_device處於link up/down狀態。

這類似於之前介紹的MMC部分的mmc card的在位檢測模式(若支持中斷則通過中斷方式通知mmc card的在位與否;若不支持中斷,則進行週期1s的延遲隊列的調度進行輪詢檢測)。但與mmc模塊不同的是,針對phy_device的狀態機對應的延遲隊列而言,不管其phy_device是否支持link up/down中斷,其狀態機對應延遲隊列均為週期1s執行(不支持中斷則由phy_device的狀態機自動切換phy的狀態進行檢測,支持中斷則由中斷處理函數中進行狀態的切換)。

如下即為執行完phy_connect操作後,針對支持phy_device中斷處理接口(phy_interrupt)以及其底半部處理接口(phy_change)與phy_state_machine之間的接口調用關聯。


LINUX PHY狀態機分析及其與net_device的關聯(MDIO模塊分析之五)

phy device的狀態機

在調用phy_connect完成net_device與phy_device的關聯後,則啟動phy_device的狀態機流轉對應的延遲隊列調度接口,進行phy_device的狀態流轉操作。如下圖為phy_device的狀態流程圖,下面詳細說明下各狀態的流轉說明:

  1. 當調用phy_device_create創建一個phy_device或者調用phy_remove移除phy_device時,即將phy_device的狀態設置為PHY_DOWN;
  2. PHY_START狀態,目前在linux3.10的內核中,沒有將phy_device的狀態切換至PHY_START步驟,因此先跳過;
  3. 當調用phy_connect完成phy_device與net_device的綁定後,即將phy_device的狀態設置為PHY_READY狀態;或者在phy_device_register、phy_driver_register時完成phy_device與phy_driver的綁定後,也會將其狀態設置為PHY_READY。
  4. 當系統調用phy_start接口,且其狀態為PHY_READY時,則將其狀態流轉至PHY_UP狀態(一般在net_device->net_ops->ndo_start中,完成phy_connect調用後,則調用phy_start將phy狀態流轉至PHY_UP);
  5. 在PHY_UP狀態時,若該phy_device設置了自適應,則自動將其狀態流轉至PHY_AN;若該PHY_DEVICE設置為FORCE狀態,則自動將其狀態流轉至PHY_FORCING;
  6. 在PHY_AN狀態下,根據讀取的phy_device的狀態寄存器,若linkup,則將其狀態流轉至PHY_RUNNING;否則將其狀態流轉至PHY_NOLINK;
  7. 在PHY_NOLINK狀態下,根據讀取的phy_device的狀態寄存器,若linkup,則將其狀態流轉至PHY_RUNNING;
  8. 在PHY_FORCING狀態下,若讀取phy_device的狀態寄存器,為linkup,則將其狀態流轉至PHY_RUNNING;
  9. PHY_RUNNING狀態下,若phy_device不支持中斷,則將其狀態設置為PHY_CHANGELINK,進行phy_device linkup狀態的輪詢檢測;
  10. 在PHY_CHANGELINK狀態下,根據讀取的phy_device的狀態寄存器,若linkup,則將其狀態流轉至PHY_RUNNING;否則則將其狀態設置為PHY_NOLINK;
  11. 當各驅動模塊調用phy_stop接口後,則phy_device的狀態跳轉至PHY_HALTED狀態(無條件跳轉,一般在net_device->netdev_ops->ndo_stop中會調用phy_stop);
  12. 僅在phy_device處於PHY_HALTED狀態時,方才會流轉至該PHY_RESUMING狀態,該狀態可跳轉至PHY_AN、PHY_NOLINK、PHY_RUNNING。


LINUX PHY狀態機分析及其與net_device的關聯(MDIO模塊分析之五)

以上即為phy_device的狀態,當phy_device處於PHY_RUNNING狀態時(此時調用netif_carrier_on設置net_device狀態),說明兩端的phy協商成功,可進行數據通信。以上phy_device的狀態流轉由接口phy_state_machine實現,該接口的流程圖如下:

主要說明如下:

  1. 當phy_device處於PHY_UP狀態時,則phy_device狀態機處理接口,設置needs_aneg為1,調用phy_start_ange接口,進入PHY_AN狀態或PHY_FORCING狀態,進行phy_device的狀態的協商;
  2. 在PHY_AN狀態時,則phy_state_machine判斷是否需要將狀態跳轉至PHY_RUNNING或PHY_NOLINK;
  3. 在PHY_RUNNING狀態時,若phy_device不支持中斷,則將其狀態跳轉至PHY_CHANNGELINK狀態,由phy_state_machine接口來輪詢判斷phy_device的狀態是否跳轉至PHY_RUNNING/PHY_NOLINK;

而像PHY_DOWN、PHY_START、PHY_READY、PHY_UP、PHY_HALTED、PHY_RESUMING這幾個狀態,一般由外部模塊調用相應的接口進行跳轉,而非phy_state_machine自動流轉。


LINUX PHY狀態機分析及其與net_device的關聯(MDIO模塊分析之五)

針對net_device也有相應的狀態定義,如下圖所示主要涉及如下幾個狀態

<code>\tenum netdev_state_t {
\t\t__LINK_STATE_START,
\t\t__LINK_STATE_PRESENT,
\t\t__LINK_STATE_NOCARRIER,
\t\t__LINK_STATE_LINKWATCH_PENDING,
\t\t__LINK_STATE_DORMANT,
};/<code>
  • 當net_device註冊至系統時,即設置__LINK_STATE_PRESENT;
  • 當執行ifconfig xxx up,啟用一個net_device時,則將其狀態設置為__LINK_STATE_START(記住此時並不代表phy已完成協商且處於linkup狀態),並在調用net_device->netdev_ops->ndo_open時,設置__LINK_STATE_NOCARRIER;
  • 當調用phy_connect完成phy_device與net_device的綁定以及啟動phy_device的狀態機後,且phy_device跳轉至PHY_RUNNING的同時,清除__LINK_STATE_NOCARRIER位,此時方才表明可進行數據通信。
  • 結語

    以上即是本次的主要內容,主要涉及phy_device與net_device之間的關聯建立以及phy_device的狀態機流轉相關的內容。當phy_device處於PHY_RUNNING狀態時,則將net_device的狀態設置為carrier_on,即可進行mac層及mac層以上的數據通信工作。


    分享到:


    相關文章: