94fb2fb3e4e94ff24d334ab37f54211a2af74fe6
[openwrt/openwrt.git] / target / linux / generic / backport-5.4 / 715-v5.3-net-phylink-don-t-start-and-stop-SGMII-PHYs-in-SFP-m.patch
1 From b8803113537a1c1f457eba6270d46e3af305031f Mon Sep 17 00:00:00 2001
2 From: Arseny Solokha <asolokha@kb.kras.ru>
3 Date: Wed, 24 Jul 2019 20:31:39 +0700
4 Subject: [PATCH 613/660] net: phylink: don't start and stop SGMII PHYs in SFP
5 modules twice
6
7 SFP modules connected using the SGMII interface have their own PHYs which
8 are handled by the struct phylink's phydev field. On the other hand, for
9 the modules connected using 1000Base-X interface that field is not set.
10
11 Since commit ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network
12 devices and sfp cages") phylink_start() ends up setting the phydev field
13 using the sfp-bus infrastructure, which eventually calls phy_start() on it,
14 and then calling phy_start() again on the same phydev from phylink_start()
15 itself. Similar call sequence holds for phylink_stop(), only in the reverse
16 order. This results in WARNs during network interface bringup and shutdown
17 when a copper SFP module is connected, as phy_start() and phy_stop() are
18 called twice in a row for the same phy_device:
19
20 % ip link set up dev eth0
21 ------------[ cut here ]------------
22 called from state UP
23 WARNING: CPU: 1 PID: 155 at drivers/net/phy/phy.c:895 phy_start+0x74/0xc0
24 Modules linked in:
25 CPU: 1 PID: 155 Comm: backend Not tainted 5.2.0+ #1
26 NIP: c0227bf0 LR: c0227bf0 CTR: c004d224
27 REGS: df547720 TRAP: 0700 Not tainted (5.2.0+)
28 MSR: 00029000 <CE,EE,ME> CR: 24002822 XER: 00000000
29
30 GPR00: c0227bf0 df5477d8 df5d7080 00000014 df9d2370 df9d5ac4 1f4eb000 00000001
31 GPR08: c061fe58 00000000 00000000 df5477d8 0000003c 100c8768 00000000 00000000
32 GPR16: df486a00 c046f1c8 c046eea0 00000000 c046e904 c0239604 db68449c 00000000
33 GPR24: e9083204 00000000 00000001 db684460 e9083404 00000000 db6dce00 db6dcc00
34 NIP [c0227bf0] phy_start+0x74/0xc0
35 LR [c0227bf0] phy_start+0x74/0xc0
36 Call Trace:
37 [df5477d8] [c0227bf0] phy_start+0x74/0xc0 (unreliable)
38 [df5477e8] [c023cad0] startup_gfar+0x398/0x3f4
39 [df547828] [c023cf08] gfar_enet_open+0x364/0x374
40 [df547898] [c029d870] __dev_open+0xe4/0x140
41 [df5478c8] [c029db70] __dev_change_flags+0xf0/0x188
42 [df5478f8] [c029dc28] dev_change_flags+0x20/0x54
43 [df547918] [c02ae304] do_setlink+0x310/0x818
44 [df547a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0
45 [df547c28] [c02b222c] rtnl_newlink+0x48/0x68
46 [df547c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c
47 [df547c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0
48 [df547cd8] [c02cba3c] netlink_unicast+0x114/0x19c
49 [df547d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0
50 [df547d58] [c027b668] sock_sendmsg_nosec+0x20/0x40
51 [df547d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc
52 [df547e98] [c027df7c] __sys_sendmsg+0x68/0x84
53 [df547ef8] [c027e430] sys_socketcall+0x1a0/0x204
54 [df547f38] [c000d1d8] ret_from_syscall+0x0/0x38
55 --- interrupt: c01 at 0xfd4e030
56 LR = 0xfd4e010
57 Instruction dump:
58 813f0188 38800000 2b890005 419d0014 3d40c046 5529103a 394aa208 7c8a482e
59 3c60c046 3863a1b8 4cc63182 4be009a1 <0fe00000> 48000030 3c60c046 3863a1d0
60 ---[ end trace d4c095aeaf6ea998 ]---
61
62 and
63
64 % ip link set down dev eth0
65 ------------[ cut here ]------------
66 called from state HALTED
67 WARNING: CPU: 1 PID: 184 at drivers/net/phy/phy.c:858 phy_stop+0x3c/0x88
68
69 <...>
70
71 Call Trace:
72 [df581788] [c0228450] phy_stop+0x3c/0x88 (unreliable)
73 [df581798] [c022d548] sfp_sm_phy_detach+0x1c/0x44
74 [df5817a8] [c022e8cc] sfp_sm_event+0x4b0/0x87c
75 [df581848] [c022f04c] sfp_upstream_stop+0x34/0x44
76 [df581858] [c0225608] phylink_stop+0x7c/0xe4
77 [df581868] [c023c57c] stop_gfar+0x7c/0x94
78 [df581888] [c023c5b8] gfar_close+0x24/0x94
79 [df5818a8] [c0298688] __dev_close_many+0xdc/0xf8
80 [df5818c8] [c029db58] __dev_change_flags+0xd8/0x188
81 [df5818f8] [c029dc28] dev_change_flags+0x20/0x54
82 [df581918] [c02ae304] do_setlink+0x310/0x818
83 [df581a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0
84 [df581c28] [c02b222c] rtnl_newlink+0x48/0x68
85 [df581c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c
86 [df581c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0
87 [df581cd8] [c02cba3c] netlink_unicast+0x114/0x19c
88 [df581d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0
89 [df581d58] [c027b668] sock_sendmsg_nosec+0x20/0x40
90 [df581d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc
91 [df581e98] [c027df7c] __sys_sendmsg+0x68/0x84
92 [df581ef8] [c027e430] sys_socketcall+0x1a0/0x204
93 [df581f38] [c000d1d8] ret_from_syscall+0x0/0x38
94
95 <...>
96
97 ---[ end trace d4c095aeaf6ea999 ]---
98
99 SFP modules with the 1000Base-X interface are not affected.
100
101 Place explicit calls to phy_start() and phy_stop() before enabling or after
102 disabling an attached SFP module, where phydev is not yet set (or is
103 already unset), so they will be made only from the inside of sfp-bus, if
104 needed.
105
106 Fixes: 217962615662 ("net: phy: warn if phy_start is called from invalid state")
107 Signed-off-by: Arseny Solokha <asolokha@kb.kras.ru>
108 Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
109 Signed-off-by: David S. Miller <davem@davemloft.net>
110 ---
111 drivers/net/phy/phylink.c | 8 ++++----
112 1 file changed, 4 insertions(+), 4 deletions(-)
113
114 --- a/drivers/net/phy/phylink.c
115 +++ b/drivers/net/phy/phylink.c
116 @@ -973,10 +973,10 @@ void phylink_start(struct phylink *pl)
117 }
118 if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
119 mod_timer(&pl->link_poll, jiffies + HZ);
120 - if (pl->sfp_bus)
121 - sfp_upstream_start(pl->sfp_bus);
122 if (pl->phydev)
123 phy_start(pl->phydev);
124 + if (pl->sfp_bus)
125 + sfp_upstream_start(pl->sfp_bus);
126 }
127 EXPORT_SYMBOL_GPL(phylink_start);
128
129 @@ -993,10 +993,10 @@ void phylink_stop(struct phylink *pl)
130 {
131 ASSERT_RTNL();
132
133 - if (pl->phydev)
134 - phy_stop(pl->phydev);
135 if (pl->sfp_bus)
136 sfp_upstream_stop(pl->sfp_bus);
137 + if (pl->phydev)
138 + phy_stop(pl->phydev);
139 del_timer_sync(&pl->link_poll);
140 if (pl->link_irq) {
141 free_irq(pl->link_irq, pl);