diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2018-02-27 10:52:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-02-28 11:07:11 -0500 |
commit | 03145864bd0fcac29e33442f39d67d4f28b0777c (patch) | |
tree | ef7dea10a328ff159c875fd6d3dbb7963d063756 | |
parent | 44d15d930bb8463d10b05bbed45e881e5055495a (diff) |
sfp: support 1G BiDi (eg, FiberStore SFP-GE-BX) modules
Some BiDi modules (eg, FiberStore SFP-GE-BX) are not compliant with
1000BASE-BX as they use different wavelengths from the 1000BASE-BX
standard (eg, 1310nm/1550nm rather than 1310nm/1490nm). These modules
support 1000BASE-X ethernet, so detect them by a failure to find any
other support, the 8B10B encoding and a bit rate that falls within the
1Gbps window.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/sfp-bus.c | 61 |
1 files changed, 38 insertions, 23 deletions
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 8961209ee949..15749428679e 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c | |||
@@ -180,10 +180,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, | |||
180 | unsigned long *support) | 180 | unsigned long *support) |
181 | { | 181 | { |
182 | unsigned int br_min, br_nom, br_max; | 182 | unsigned int br_min, br_nom, br_max; |
183 | 183 | __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, }; | |
184 | phylink_set(support, Autoneg); | ||
185 | phylink_set(support, Pause); | ||
186 | phylink_set(support, Asym_Pause); | ||
187 | 184 | ||
188 | /* Decode the bitrate information to MBd */ | 185 | /* Decode the bitrate information to MBd */ |
189 | br_min = br_nom = br_max = 0; | 186 | br_min = br_nom = br_max = 0; |
@@ -201,20 +198,20 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, | |||
201 | 198 | ||
202 | /* Set ethtool support from the compliance fields. */ | 199 | /* Set ethtool support from the compliance fields. */ |
203 | if (id->base.e10g_base_sr) | 200 | if (id->base.e10g_base_sr) |
204 | phylink_set(support, 10000baseSR_Full); | 201 | phylink_set(modes, 10000baseSR_Full); |
205 | if (id->base.e10g_base_lr) | 202 | if (id->base.e10g_base_lr) |
206 | phylink_set(support, 10000baseLR_Full); | 203 | phylink_set(modes, 10000baseLR_Full); |
207 | if (id->base.e10g_base_lrm) | 204 | if (id->base.e10g_base_lrm) |
208 | phylink_set(support, 10000baseLRM_Full); | 205 | phylink_set(modes, 10000baseLRM_Full); |
209 | if (id->base.e10g_base_er) | 206 | if (id->base.e10g_base_er) |
210 | phylink_set(support, 10000baseER_Full); | 207 | phylink_set(modes, 10000baseER_Full); |
211 | if (id->base.e1000_base_sx || | 208 | if (id->base.e1000_base_sx || |
212 | id->base.e1000_base_lx || | 209 | id->base.e1000_base_lx || |
213 | id->base.e1000_base_cx) | 210 | id->base.e1000_base_cx) |
214 | phylink_set(support, 1000baseX_Full); | 211 | phylink_set(modes, 1000baseX_Full); |
215 | if (id->base.e1000_base_t) { | 212 | if (id->base.e1000_base_t) { |
216 | phylink_set(support, 1000baseT_Half); | 213 | phylink_set(modes, 1000baseT_Half); |
217 | phylink_set(support, 1000baseT_Full); | 214 | phylink_set(modes, 1000baseT_Full); |
218 | } | 215 | } |
219 | 216 | ||
220 | /* 1000Base-PX or 1000Base-BX10 */ | 217 | /* 1000Base-PX or 1000Base-BX10 */ |
@@ -228,20 +225,20 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, | |||
228 | if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) { | 225 | if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) { |
229 | /* This may look odd, but some manufacturers use 12000MBd */ | 226 | /* This may look odd, but some manufacturers use 12000MBd */ |
230 | if (br_min <= 12000 && br_max >= 10300) | 227 | if (br_min <= 12000 && br_max >= 10300) |
231 | phylink_set(support, 10000baseCR_Full); | 228 | phylink_set(modes, 10000baseCR_Full); |
232 | if (br_min <= 3200 && br_max >= 3100) | 229 | if (br_min <= 3200 && br_max >= 3100) |
233 | phylink_set(support, 2500baseX_Full); | 230 | phylink_set(modes, 2500baseX_Full); |
234 | if (br_min <= 1300 && br_max >= 1200) | 231 | if (br_min <= 1300 && br_max >= 1200) |
235 | phylink_set(support, 1000baseX_Full); | 232 | phylink_set(modes, 1000baseX_Full); |
236 | } | 233 | } |
237 | if (id->base.sfp_ct_passive) { | 234 | if (id->base.sfp_ct_passive) { |
238 | if (id->base.passive.sff8431_app_e) | 235 | if (id->base.passive.sff8431_app_e) |
239 | phylink_set(support, 10000baseCR_Full); | 236 | phylink_set(modes, 10000baseCR_Full); |
240 | } | 237 | } |
241 | if (id->base.sfp_ct_active) { | 238 | if (id->base.sfp_ct_active) { |
242 | if (id->base.active.sff8431_app_e || | 239 | if (id->base.active.sff8431_app_e || |
243 | id->base.active.sff8431_lim) { | 240 | id->base.active.sff8431_lim) { |
244 | phylink_set(support, 10000baseCR_Full); | 241 | phylink_set(modes, 10000baseCR_Full); |
245 | } | 242 | } |
246 | } | 243 | } |
247 | 244 | ||
@@ -249,18 +246,18 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, | |||
249 | case 0x00: /* Unspecified */ | 246 | case 0x00: /* Unspecified */ |
250 | break; | 247 | break; |
251 | case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */ | 248 | case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */ |
252 | phylink_set(support, 100000baseSR4_Full); | 249 | phylink_set(modes, 100000baseSR4_Full); |
253 | phylink_set(support, 25000baseSR_Full); | 250 | phylink_set(modes, 25000baseSR_Full); |
254 | break; | 251 | break; |
255 | case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */ | 252 | case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */ |
256 | case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */ | 253 | case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */ |
257 | phylink_set(support, 100000baseLR4_ER4_Full); | 254 | phylink_set(modes, 100000baseLR4_ER4_Full); |
258 | break; | 255 | break; |
259 | case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */ | 256 | case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */ |
260 | case 0x0c: /* 25Gbase-CR CA-S */ | 257 | case 0x0c: /* 25Gbase-CR CA-S */ |
261 | case 0x0d: /* 25Gbase-CR CA-N */ | 258 | case 0x0d: /* 25Gbase-CR CA-N */ |
262 | phylink_set(support, 100000baseCR4_Full); | 259 | phylink_set(modes, 100000baseCR4_Full); |
263 | phylink_set(support, 25000baseCR_Full); | 260 | phylink_set(modes, 25000baseCR_Full); |
264 | break; | 261 | break; |
265 | default: | 262 | default: |
266 | dev_warn(bus->sfp_dev, | 263 | dev_warn(bus->sfp_dev, |
@@ -274,10 +271,28 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, | |||
274 | id->base.fc_speed_200 || | 271 | id->base.fc_speed_200 || |
275 | id->base.fc_speed_400) { | 272 | id->base.fc_speed_400) { |
276 | if (id->base.br_nominal >= 31) | 273 | if (id->base.br_nominal >= 31) |
277 | phylink_set(support, 2500baseX_Full); | 274 | phylink_set(modes, 2500baseX_Full); |
278 | if (id->base.br_nominal >= 12) | 275 | if (id->base.br_nominal >= 12) |
279 | phylink_set(support, 1000baseX_Full); | 276 | phylink_set(modes, 1000baseX_Full); |
280 | } | 277 | } |
278 | |||
279 | /* If we haven't discovered any modes that this module supports, try | ||
280 | * the encoding and bitrate to determine supported modes. Some BiDi | ||
281 | * modules (eg, 1310nm/1550nm) are not 1000BASE-BX compliant due to | ||
282 | * the differing wavelengths, so do not set any transceiver bits. | ||
283 | */ | ||
284 | if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) { | ||
285 | /* If the encoding and bit rate allows 1000baseX */ | ||
286 | if (id->base.encoding == SFP_ENCODING_8B10B && br_nom && | ||
287 | br_min <= 1300 && br_max >= 1200) | ||
288 | phylink_set(modes, 1000baseX_Full); | ||
289 | } | ||
290 | |||
291 | bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS); | ||
292 | |||
293 | phylink_set(support, Autoneg); | ||
294 | phylink_set(support, Pause); | ||
295 | phylink_set(support, Asym_Pause); | ||
281 | } | 296 | } |
282 | EXPORT_SYMBOL_GPL(sfp_parse_support); | 297 | EXPORT_SYMBOL_GPL(sfp_parse_support); |
283 | 298 | ||