octeon: disable edgerouter image
[openwrt/openwrt.git] / target / linux / generic / pending-4.19 / 750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch
1 From eb514428f75bc67d12ff019c44a8f8ca9f33c54c Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@armlinux.org.uk>
3 Date: Thu, 21 Nov 2019 17:42:49 +0000
4 Subject: [PATCH 653/660] net: phylink: delay MAC configuration for copper SFP
5 modules
6
7 Knowing whether we need to delay the MAC configuration because a module
8 may have a PHY is useful to phylink to allow NBASE-T modules to work on
9 systems supporting no more than 2.5G speeds.
10
11 This commit allows us to delay such configuration until after the PHY
12 has been probed by recording the parsed capabilities, and if the module
13 may have a PHY, doing no more until the module_start() notification is
14 called. At that point, we either have a PHY, or we don't.
15
16 We move the PHY-based setup a little later, and use the PHYs support
17 capabilities rather than the EEPROM parsed capabilities to determine
18 whether we can support the PHY.
19
20 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
21 ---
22 drivers/net/phy/phylink.c | 59 +++++++++++++++++++++++++++++++--------
23 drivers/net/phy/sfp-bus.c | 28 +++++++++++++++++++
24 include/linux/sfp.h | 7 +++++
25 3 files changed, 83 insertions(+), 11 deletions(-)
26
27 --- a/drivers/net/phy/phylink.c
28 +++ b/drivers/net/phy/phylink.c
29 @@ -72,6 +72,9 @@ struct phylink {
30 bool mac_link_dropped;
31
32 struct sfp_bus *sfp_bus;
33 + bool sfp_may_have_phy;
34 + __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
35 + u8 sfp_port;
36 };
37
38 static inline void linkmode_zero(unsigned long *dst)
39 @@ -1633,7 +1636,7 @@ static void phylink_sfp_detach(void *ups
40 pl->netdev->sfp_bus = NULL;
41 }
42
43 -static int phylink_sfp_config(struct phylink *pl, u8 mode, u8 port,
44 +static int phylink_sfp_config(struct phylink *pl, u8 mode,
45 const unsigned long *supported,
46 const unsigned long *advertising)
47 {
48 @@ -1707,7 +1710,7 @@ static int phylink_sfp_config(struct phy
49 phy_modes(config.interface));
50 }
51
52 - pl->link_port = port;
53 + pl->link_port = pl->sfp_port;
54
55 if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
56 &pl->phylink_disable_state))
57 @@ -1720,15 +1723,20 @@ static int phylink_sfp_module_insert(voi
58 const struct sfp_eeprom_id *id)
59 {
60 struct phylink *pl = upstream;
61 - __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
62 - u8 port;
63 + unsigned long *support = pl->sfp_support;
64
65 ASSERT_RTNL();
66
67 + linkmode_zero(support);
68 sfp_parse_support(pl->sfp_bus, id, support);
69 - port = sfp_parse_port(pl->sfp_bus, id, support);
70 + pl->sfp_port = sfp_parse_port(pl->sfp_bus, id, support);
71
72 - return phylink_sfp_config(pl, MLO_AN_INBAND, port, support, support);
73 + /* If this module may have a PHY connecting later, defer until later */
74 + pl->sfp_may_have_phy = sfp_may_have_phy(pl->sfp_bus, id);
75 + if (pl->sfp_may_have_phy)
76 + return 0;
77 +
78 + return phylink_sfp_config(pl, MLO_AN_INBAND, support, support);
79 }
80
81 static int phylink_sfp_module_start(void *upstream)
82 @@ -1736,10 +1744,19 @@ static int phylink_sfp_module_start(void
83 struct phylink *pl = upstream;
84
85 /* If this SFP module has a PHY, start the PHY now. */
86 - if (pl->phydev)
87 + if (pl->phydev) {
88 phy_start(pl->phydev);
89 -
90 - return 0;
91 + return 0;
92 + }
93 +
94 + /* If the module may have a PHY but we didn't detect one we
95 + * need to configure the MAC here.
96 + */
97 + if (!pl->sfp_may_have_phy)
98 + return 0;
99 +
100 + return phylink_sfp_config(pl, MLO_AN_INBAND,
101 + pl->sfp_support, pl->sfp_support);
102 }
103
104 static void phylink_sfp_module_stop(void *upstream)
105 @@ -1773,10 +1790,30 @@ static void phylink_sfp_link_up(void *up
106 static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy)
107 {
108 struct phylink *pl = upstream;
109 - phy_interface_t interface = pl->link_config.interface;
110 + __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
111 + __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
112 + phy_interface_t interface;
113 int ret;
114
115 - ret = phylink_attach_phy(pl, phy, pl->link_config.interface);
116 + /*
117 + * This is the new way of dealing with flow control for PHYs,
118 + * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
119 + * phy drivers should not set SUPPORTED_[Asym_]Pause") except
120 + * using our validate call to the MAC, we rely upon the MAC
121 + * clearing the bits from both supported and advertising fields.
122 + */
123 + phy_support_asym_pause(phy);
124 +
125 + ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
126 + ethtool_convert_legacy_u32_to_link_mode(advertising, phy->advertising);
127 +
128 + /* Do the initial configuration */
129 + ret = phylink_sfp_config(pl, ML_AN_INBAND, supported, advertising);
130 + if (ret < 0)
131 + return ret;
132 +
133 + interface = pl->link_config.interface;
134 + ret = phylink_attach_phy(pl, phy, interface);
135 if (ret < 0)
136 return ret;
137
138 --- a/drivers/net/phy/sfp-bus.c
139 +++ b/drivers/net/phy/sfp-bus.c
140 @@ -102,6 +102,7 @@ static const struct sfp_quirk *sfp_looku
141
142 return NULL;
143 }
144 +
145 /**
146 * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
147 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
148 @@ -178,6 +179,33 @@ int sfp_parse_port(struct sfp_bus *bus,
149 EXPORT_SYMBOL_GPL(sfp_parse_port);
150
151 /**
152 + * sfp_may_have_phy() - indicate whether the module may have a PHY
153 + * @bus: a pointer to the &struct sfp_bus structure for the sfp module
154 + * @id: a pointer to the module's &struct sfp_eeprom_id
155 + *
156 + * Parse the EEPROM identification given in @id, and return whether
157 + * this module may have a PHY.
158 + */
159 +bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
160 +{
161 + if (id->base.e1000_base_t)
162 + return true;
163 +
164 + if (id->base.phys_id != SFF8024_ID_DWDM_SFP) {
165 + switch (id->base.extended_cc) {
166 + case SFF8024_ECC_10GBASE_T_SFI:
167 + case SFF8024_ECC_10GBASE_T_SR:
168 + case SFF8024_ECC_5GBASE_T:
169 + case SFF8024_ECC_2_5GBASE_T:
170 + return true;
171 + }
172 + }
173 +
174 + return false;
175 +}
176 +EXPORT_SYMBOL_GPL(sfp_may_have_phy);
177 +
178 +/**
179 * sfp_parse_support() - Parse the eeprom id for supported link modes
180 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
181 * @id: a pointer to the module's &struct sfp_eeprom_id
182 --- a/include/linux/sfp.h
183 +++ b/include/linux/sfp.h
184 @@ -533,6 +533,7 @@ struct sfp_upstream_ops {
185 #if IS_ENABLED(CONFIG_SFP)
186 int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
187 unsigned long *support);
188 +bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
189 void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
190 unsigned long *support);
191 phy_interface_t sfp_select_interface(struct sfp_bus *bus,
192 @@ -556,6 +557,12 @@ static inline int sfp_parse_port(struct
193 return PORT_OTHER;
194 }
195
196 +static inline bool sfp_may_have_phy(struct sfp_bus *bus,
197 + const struct sfp_eeprom_id *id)
198 +{
199 + return false;
200 +}
201 +
202 static inline void sfp_parse_support(struct sfp_bus *bus,
203 const struct sfp_eeprom_id *id,
204 unsigned long *support)