Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: at803x: use operating parameters from PHY-specific status

Read the PHY-specific status register for the current operating mode
(speed and duplex) of the PHY. This register reflects the actual
mode that the PHY has resolved depending on either the advertisements
of autoneg is enabled, or the forced mode if autoneg is disabled.

This ensures that phylib's software state always tracks the hardware
state.

It seems both AR8033 (which uses the AR8031 ID) and AR8035 support
this status register. AR8030 is not known at the present time.

This patch depends on "net: phy: extract pause mode" and "net: phy:
extract link partner advertisement reading".

Reported-by: tinywrkb <tinywrkb@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Tested-by: tinywrkb <tinywrkb@gmail.com>
Fixes: 5502b218e001 ("net: phy: use phy_resolve_aneg_linkmode in genphy_read_status")
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Russell King and committed by
David S. Miller
06d5f344 2d880b87

+69
+69
drivers/net/phy/at803x.c
··· 15 15 #include <linux/of_gpio.h> 16 16 #include <linux/gpio/consumer.h> 17 17 18 + #define AT803X_SPECIFIC_STATUS 0x11 19 + #define AT803X_SS_SPEED_MASK (3 << 14) 20 + #define AT803X_SS_SPEED_1000 (2 << 14) 21 + #define AT803X_SS_SPEED_100 (1 << 14) 22 + #define AT803X_SS_SPEED_10 (0 << 14) 23 + #define AT803X_SS_DUPLEX BIT(13) 24 + #define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) 25 + #define AT803X_SS_MDIX BIT(6) 26 + 18 27 #define AT803X_INTR_ENABLE 0x12 19 28 #define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) 20 29 #define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) ··· 366 357 return aneg_done; 367 358 } 368 359 360 + static int at803x_read_status(struct phy_device *phydev) 361 + { 362 + int ss, err, old_link = phydev->link; 363 + 364 + /* Update the link, but return if there was an error */ 365 + err = genphy_update_link(phydev); 366 + if (err) 367 + return err; 368 + 369 + /* why bother the PHY if nothing can have changed */ 370 + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) 371 + return 0; 372 + 373 + phydev->speed = SPEED_UNKNOWN; 374 + phydev->duplex = DUPLEX_UNKNOWN; 375 + phydev->pause = 0; 376 + phydev->asym_pause = 0; 377 + 378 + err = genphy_read_lpa(phydev); 379 + if (err < 0) 380 + return err; 381 + 382 + /* Read the AT8035 PHY-Specific Status register, which indicates the 383 + * speed and duplex that the PHY is actually using, irrespective of 384 + * whether we are in autoneg mode or not. 385 + */ 386 + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); 387 + if (ss < 0) 388 + return ss; 389 + 390 + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { 391 + switch (ss & AT803X_SS_SPEED_MASK) { 392 + case AT803X_SS_SPEED_10: 393 + phydev->speed = SPEED_10; 394 + break; 395 + case AT803X_SS_SPEED_100: 396 + phydev->speed = SPEED_100; 397 + break; 398 + case AT803X_SS_SPEED_1000: 399 + phydev->speed = SPEED_1000; 400 + break; 401 + } 402 + if (ss & AT803X_SS_DUPLEX) 403 + phydev->duplex = DUPLEX_FULL; 404 + else 405 + phydev->duplex = DUPLEX_HALF; 406 + if (ss & AT803X_SS_MDIX) 407 + phydev->mdix = ETH_TP_MDI_X; 408 + else 409 + phydev->mdix = ETH_TP_MDI; 410 + } 411 + 412 + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) 413 + phy_resolve_aneg_pause(phydev); 414 + 415 + return 0; 416 + } 417 + 369 418 static struct phy_driver at803x_driver[] = { 370 419 { 371 420 /* ATHEROS 8035 */ ··· 437 370 .suspend = at803x_suspend, 438 371 .resume = at803x_resume, 439 372 /* PHY_GBIT_FEATURES */ 373 + .read_status = at803x_read_status, 440 374 .ack_interrupt = at803x_ack_interrupt, 441 375 .config_intr = at803x_config_intr, 442 376 }, { ··· 467 399 .suspend = at803x_suspend, 468 400 .resume = at803x_resume, 469 401 /* PHY_GBIT_FEATURES */ 402 + .read_status = at803x_read_status, 470 403 .aneg_done = at803x_aneg_done, 471 404 .ack_interrupt = &at803x_ack_interrupt, 472 405 .config_intr = &at803x_config_intr,