linux移動文件命令,linux 命令 讀phy_Linux PHY幾個狀態的跟蹤

 2023-10-15 阅读 24 评论 0

摘要:前面文章零零星星地分析了PHY,本來想完整地,系統地做分析,發現工程量太大了,而自己又一知半解,所以只好各個擊破,一點一點來分析。本文主要分析了設備上電、撥出網線、插上網線、自動協商等過程的PHY狀態。MAC驅動和PHY驅動PHY一般

前面文章零零星星地分析了PHY,本來想完整地,系統地做分析,發現工程量太大了,而自己又一知半解,所以只好各個擊破,一點一點來分析。本文主要分析了設備上電、撥出網線、插上網線、自動協商等過程的PHY狀態。

MAC驅動和PHY驅動

PHY一般和具體的MAC控制驅動聯系一起,這里以TI的MAC驅動為例,由它切入到PHY驅動。Linux內核通過mdio總線訪問、控制PHY,源碼實現在driver/net/phy/mdio_bus.c中。下面是mdio掃描、找到并注冊phy的過程:

1

linux移動文件命令、2

3

4

5

6

python調用shell命令?7

8

9davinci_mdio_probe

->mdiobus_register

-> device_register

linux查看ip命令?-> mdiobus_scan

-> get_phy_device

-> get_phy_id // 讀寄存器

-> phy_device_create

-> INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); // !!!!!!初始化狀態機函數

linux查看進程命令?-> phy_device_register

在phy_device_create中做了大量的初始化工作,比如默認就是使能自動協商,另外調用INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine)創建phy的狀態機,——實際上它是一個延時工作隊列。

cpsw驅動在net_device_ops的ndo_open函數,亦即cpsw_ndo_open中調用cpsw_slave_open,通過phy_connect與phy連接,同時將cpsw_adjust_link賦值給phy的狀態調整函數指針adjust_link。在些過程將將PHY狀態機開啟。

這個過程主要的函數如下:

1

linux基本命令的使用、2

3

4

5

6

linux進程狀態?7cpsw_ndo_open

-> cpsw_slave_open

-> phy_connect (傳遞cpsw_adjust_link)

-> phy_connect_direct (PHY_READY)

-> phy_prepare_link (賦值cpsw_adjust_link為adjust_link)

python異步調用shell、-> phy_start_machine

-> phy_start (PHY_READY變成PHY_UP)

當系統啟動時,經過上述的步驟,一切已經準備妥當。就等著迎接PHY的狀態變更了。在這里,需要提及的函數是cpsw_adjust_link,它調用了_cpsw_adjust_link,之后通知內核其它網絡模塊當前的狀態。這個函數將在phy狀態機函數中時時被調用,所以要關注一下。代碼如下:

1

2

linux數據庫命令。3

4

5

6

7

linux新建用戶命令。8

9

10

11

12

linux su命令、13

14

15

16static void cpsw_adjust_link(struct net_device *ndev)

{

linux必學的60個命令?struct cpsw_priv *priv = netdev_priv(ndev);

bool link = false;

for_each_slave(priv, _cpsw_adjust_link, priv, &link);

if (link) {

netif_carrier_on(ndev); // 通知內核子系統網絡,當前鏈接是OK的

shell運行python腳本,if (netif_running(ndev))

netif_wake_queue(ndev);

} else {

netif_carrier_off(ndev); // 通知內核子系統網絡,當前鏈接斷開了

netif_stop_queue(ndev);

linux重啟網絡命令,}

}

真正干活(設置)的是這個函數:

1

2

linux如何查看進程,3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45static void _cpsw_adjust_link(struct cpsw_slave *slave,

struct cpsw_priv *priv, bool *link)

{

struct phy_device *phy = slave->phy;

u32 mac_control = 0;

u32 slave_port;

if (!phy)

return;

slave_port = cpsw_get_slave_port(priv, slave->slave_num);

if (phy->link) {

mac_control = priv->data.mac_control;

/* enable forwarding */

cpsw_ale_control_set(priv->ale, slave_port,

ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);

if (phy->speed == 1000) // 千兆

mac_control |= BIT(7); /* GIGABITEN */

if (phy->duplex)

mac_control |= BIT(0); /* FULLDUPLEXEN */

/* set speed_in input in case RMII mode is used in 100Mbps */

if (phy->speed == 100) // 百兆

mac_control |= BIT(15);

else if (phy->speed == 10) // 十兆

mac_control |= BIT(18); /* In Band mode */

*link = true;

} else {

mac_control = 0;

/* disable forwarding */

cpsw_ale_control_set(priv->ale, slave_port,

ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);

}

if (mac_control != slave->mac_control) {

phy_print_status(phy); // 當狀態不同時,需要寫寄存器時,才打印網絡狀態

__raw_writel(mac_control, &slave->sliver->mac_control);

}

slave->mac_control = mac_control;

}

它實際上寫mac_control寄存器,這個寄存器控制著速率(千兆、百兆、十兆)和雙工。之前不太理解,問了高手,才知道不單單要設置PHY寄存器,還要設置mac控制模塊的寄存器。phy_print_status是phy驅動的通用函數,用以打印網絡狀態(初步查了下,像Intel的網絡驅動,不調用此函數,等有空再研究研究)。

1

2

3

4

5

6

7

8

9

10

11

12void phy_print_status(struct phy_device *phydev)

{

if (phydev->link) {

netdev_info(phydev->attached_dev,

"Link is Up - %s/%s - flow control %s\n",

phy_speed_to_str(phydev->speed),

DUPLEX_FULL == phydev->duplex ? "Full" : "Half",

phydev->pause ? "rx/tx" : "off");

} else {

netdev_info(phydev->attached_dev, "Link is Down\n");

}

}

其中的phy_speed_to_str函數是將網速轉化成字符串,在內核的舊版本上是沒有的。 當網絡連接時,會打印如下信息:

1PHY: 2:50 - Link is Up - 100Mbps/Full - flow control off

當網絡斷開時,會打印:

1PHY: 2:50 - Link is Down

PHY狀態機

先看看PHY有的狀態定義:

1

2

3

4

5

6

7

8

9

10

11

12

13

14enum phy_state {

PHY_DOWN = 0, // PHY芯片和驅動沒準備好,一般情況下少發生

PHY_STARTING, // PHY芯片OK了,但驅動還沒有準備好

PHY_READY, // 準備好了,在probe中賦值,接下來會切到PHY_UP

PHY_PENDING,

PHY_UP, // phy啟動了,可以工作了,接下來會到PHY_AN

PHY_AN, // 自動協商

PHY_RUNNING, // 正在運行中,在網絡連接(插上網線)時會到這個狀態

PHY_NOLINK, // 斷網了

PHY_FORCING, // 強制,當自動協商不使能時,就會進行此狀態(實際上會讀PHY寄存器進行設置速率、雙工,等)

PHY_CHANGELINK, // 變化,這個狀態很重要,當連接時,會換到PHY_RUNNING,當斷網時,會切到PHY_NOLINK

PHY_HALTED,

PHY_RESUMING

};

phy狀態變化主要在phy_state_machine函數,該函數一直在運行(每隔一秒檢測一次網絡狀態),該函數判斷不同的網絡狀態作出不同的動作。其中CHANGELINK是會根據網絡連、斷來判斷是RUNNING還是NOLINK。這樣,就知道網絡是連接上還是斷開。當連接上網絡后(注:不斷開情況),狀態為RUNNING時,之后重新賦值CHANGELINK,到了CHANGELINK又賦值RUNNING,這兩種狀態之間不斷切換。完整代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192/**

* 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, do_resume = 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:

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); // 讀phy狀態,包括link,速率、雙工,等等

if (err < 0)

break;

/* If the link is down, give up on negotiation for now */

if (!phydev->link) {

phydev->state = PHY_NOLINK; // 沒有連接,則狀態變成PHY_NOLINK

netif_carrier_off(phydev->attached_dev); // 通知內核其它網絡模塊(phy是最底一層)斷網了。

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; // 完成后,變成PHY_RUNNING狀態

netif_carrier_on(phydev->attached_dev); // 發通知,連接OK

phydev->adjust_link(phydev->attached_dev); // 打印、調用參數

} else if (0 == phydev->link_timeout--)

needs_aneg = true;

break;

case PHY_NOLINK:

err = phy_read_status(phydev); // 讀phy狀態,包括link,速率、雙工,等等

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; // 如果是RUNNING,則改變為CHANGELINK。

break;

case PHY_CHANGELINK:

err = phy_read_status(phydev); // 讀phy狀態,包括link,速率、雙工,等等

if (err)

break;

if (phydev->link) {

phydev->state = PHY_RUNNING; // 連接網絡時,則變成RUNNING

netif_carrier_on(phydev->attached_dev);

} else {

phydev->state = PHY_NOLINK; // 不連網時,變成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:

err = phy_clear_interrupt(phydev);

if (err)

break;

err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);

if (err)

break;

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); // 讀phy狀態,包括link,速率、雙工,等等

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

}

do_resume = true;

break;

}

mutex_unlock(&phydev->lock);

if (needs_aneg)

err = phy_start_aneg(phydev);

else if (do_suspend)

phy_suspend(phydev);

else if (do_resume)

phy_resume(phydev);

if (err < 0)

phy_error(phydev);

queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,

PHY_STATE_TIME * HZ);

}

經過一大段的分析研究后,當網絡發生變化時,就十分清晰了。

PHY狀態

上電時狀態變化:

1PHY_READY -> PHY_UP -> PHY_AN -> PHY_RUNNING

撥出網線時狀態變化:

1PHY_RUNNING ->PHY_NOLINK

插上網線時狀態變化:

1PHY_NOLINK -> PHY_RUNNING

自動協商過程:

1cpsw_ndo_open->cpsw_slave_open -> PHY_UP -> phy_start_aneg -> genphy_config_aneg -> genphy_config_advert -> genphy_restart_aneg -> PHY_AN -> PHY_NOLINK(串口打印Down) -> phy_aneg_done -> PHY_RUNNING(串口打印Up)

注:在AN后出現NOLINK狀態,我猜是因為自動協商需要時間,此時間大于1秒,然后執行到狀態機判斷成NOLINK,然后判斷是否完成自動協商,然后再到RUNNING狀態。

2015年4月6日,李遲,于清明假期

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/137804.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息