Skip to content

Commit d7029f5

Browse files
Ivan Bornyakovdavem330
authored andcommitted
net: phy: marvell-88x2222: swap 1G/10G modes on autoneg
Setting 10G without autonegotiation is invalid according to phy_ethtool_ksettings_set(). Thus, we need to set it during autonegotiation. If 1G autonegotiation can't complete for quite a time, but there is signal in line, switch line interface type to 10GBase-R, if supported, in hope for link to be established. And vice versa. If 10GBase-R link can't be established for quite a time, and autonegotiation is enabled, and there is signal in line, switch line interface type to appropriate 1G mode, i.e. 1000Base-X or SGMII, if supported. Signed-off-by: Ivan Bornyakov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 473960a commit d7029f5

File tree

1 file changed

+89
-28
lines changed

1 file changed

+89
-28
lines changed

drivers/net/phy/marvell-88x2222.c

Lines changed: 89 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
#define MV_1GBX_PHY_STAT_SPEED100 BIT(14)
5353
#define MV_1GBX_PHY_STAT_SPEED1000 BIT(15)
5454

55+
#define AUTONEG_TIMEOUT 3
56+
5557
struct mv2222_data {
5658
phy_interface_t line_interface;
5759
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
@@ -173,6 +175,24 @@ static bool mv2222_is_1gbx_capable(struct phy_device *phydev)
173175
priv->supported);
174176
}
175177

178+
static bool mv2222_is_sgmii_capable(struct phy_device *phydev)
179+
{
180+
struct mv2222_data *priv = phydev->priv;
181+
182+
return (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
183+
priv->supported) ||
184+
linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
185+
priv->supported) ||
186+
linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
187+
priv->supported) ||
188+
linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
189+
priv->supported) ||
190+
linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
191+
priv->supported) ||
192+
linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
193+
priv->supported));
194+
}
195+
176196
static int mv2222_config_line(struct phy_device *phydev)
177197
{
178198
struct mv2222_data *priv = phydev->priv;
@@ -192,33 +212,32 @@ static int mv2222_config_line(struct phy_device *phydev)
192212
}
193213
}
194214

195-
static int mv2222_setup_forced(struct phy_device *phydev)
215+
/* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */
216+
static int mv2222_swap_line_type(struct phy_device *phydev)
196217
{
197218
struct mv2222_data *priv = phydev->priv;
198219
bool changed = false;
199220
int ret;
200221

201222
switch (priv->line_interface) {
202223
case PHY_INTERFACE_MODE_10GBASER:
203-
if (phydev->speed == SPEED_1000 &&
204-
mv2222_is_1gbx_capable(phydev)) {
224+
if (mv2222_is_1gbx_capable(phydev)) {
205225
priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
206226
changed = true;
207227
}
208228

209-
break;
210-
case PHY_INTERFACE_MODE_1000BASEX:
211-
if (phydev->speed == SPEED_10000 &&
212-
mv2222_is_10g_capable(phydev)) {
213-
priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
229+
if (mv2222_is_sgmii_capable(phydev)) {
230+
priv->line_interface = PHY_INTERFACE_MODE_SGMII;
214231
changed = true;
215232
}
216233

217234
break;
235+
case PHY_INTERFACE_MODE_1000BASEX:
218236
case PHY_INTERFACE_MODE_SGMII:
219-
ret = mv2222_set_sgmii_speed(phydev);
220-
if (ret < 0)
221-
return ret;
237+
if (mv2222_is_10g_capable(phydev)) {
238+
priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
239+
changed = true;
240+
}
222241

223242
break;
224243
default:
@@ -231,6 +250,29 @@ static int mv2222_setup_forced(struct phy_device *phydev)
231250
return ret;
232251
}
233252

253+
return 0;
254+
}
255+
256+
static int mv2222_setup_forced(struct phy_device *phydev)
257+
{
258+
struct mv2222_data *priv = phydev->priv;
259+
int ret;
260+
261+
if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) {
262+
if (phydev->speed < SPEED_10000 &&
263+
phydev->speed != SPEED_UNKNOWN) {
264+
ret = mv2222_swap_line_type(phydev);
265+
if (ret < 0)
266+
return ret;
267+
}
268+
}
269+
270+
if (priv->line_interface == PHY_INTERFACE_MODE_SGMII) {
271+
ret = mv2222_set_sgmii_speed(phydev);
272+
if (ret < 0)
273+
return ret;
274+
}
275+
234276
return mv2222_disable_aneg(phydev);
235277
}
236278

@@ -244,17 +286,9 @@ static int mv2222_config_aneg(struct phy_device *phydev)
244286
return 0;
245287

246288
if (phydev->autoneg == AUTONEG_DISABLE ||
247-
phydev->speed == SPEED_10000)
289+
priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
248290
return mv2222_setup_forced(phydev);
249291

250-
if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER &&
251-
mv2222_is_1gbx_capable(phydev)) {
252-
priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
253-
ret = mv2222_config_line(phydev);
254-
if (ret < 0)
255-
return ret;
256-
}
257-
258292
adv = linkmode_adv_to_mii_adv_x(priv->supported,
259293
ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
260294

@@ -291,6 +325,7 @@ static int mv2222_aneg_done(struct phy_device *phydev)
291325
/* Returns negative on error, 0 if link is down, 1 if link is up */
292326
static int mv2222_read_status_10g(struct phy_device *phydev)
293327
{
328+
static int timeout;
294329
int val, link = 0;
295330

296331
val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
@@ -304,6 +339,20 @@ static int mv2222_read_status_10g(struct phy_device *phydev)
304339
phydev->autoneg = AUTONEG_DISABLE;
305340
phydev->speed = SPEED_10000;
306341
phydev->duplex = DUPLEX_FULL;
342+
} else {
343+
if (phydev->autoneg == AUTONEG_ENABLE) {
344+
timeout++;
345+
346+
if (timeout > AUTONEG_TIMEOUT) {
347+
timeout = 0;
348+
349+
val = mv2222_swap_line_type(phydev);
350+
if (val < 0)
351+
return val;
352+
353+
return mv2222_config_aneg(phydev);
354+
}
355+
}
307356
}
308357

309358
return link;
@@ -312,15 +361,31 @@ static int mv2222_read_status_10g(struct phy_device *phydev)
312361
/* Returns negative on error, 0 if link is down, 1 if link is up */
313362
static int mv2222_read_status_1g(struct phy_device *phydev)
314363
{
364+
static int timeout;
315365
int val, link = 0;
316366

317367
val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
318368
if (val < 0)
319369
return val;
320370

321-
if (!(val & BMSR_LSTATUS) ||
322-
(phydev->autoneg == AUTONEG_ENABLE &&
323-
!(val & BMSR_ANEGCOMPLETE)))
371+
if (phydev->autoneg == AUTONEG_ENABLE &&
372+
!(val & BMSR_ANEGCOMPLETE)) {
373+
timeout++;
374+
375+
if (timeout > AUTONEG_TIMEOUT) {
376+
timeout = 0;
377+
378+
val = mv2222_swap_line_type(phydev);
379+
if (val < 0)
380+
return val;
381+
382+
return mv2222_config_aneg(phydev);
383+
}
384+
385+
return 0;
386+
}
387+
388+
if (!(val & BMSR_LSTATUS))
324389
return 0;
325390

326391
link = 1;
@@ -447,11 +512,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
447512
return ret;
448513

449514
if (mutex_trylock(&phydev->lock)) {
450-
if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
451-
ret = mv2222_setup_forced(phydev);
452-
else
453-
ret = mv2222_config_aneg(phydev);
454-
515+
ret = mv2222_config_aneg(phydev);
455516
mutex_unlock(&phydev->lock);
456517
}
457518

0 commit comments

Comments
 (0)