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

net: phy: micrel: Discern KSZ8051 and KSZ8795 PHYs

The KSZ8051 PHY and the KSZ8794/KSZ8795/KSZ8765 switch share exactly the
same PHY ID. Since KSZ8051 is higher in the ksphy_driver[] list of PHYs
in the micrel PHY driver, it is used even with the KSZ87xx switch. This
is wrong, since the KSZ8051 configures registers of the PHY which are
not present on the simplified KSZ87xx switch PHYs and misconfigures
other registers of the KSZ87xx switch PHYs.

Fortunatelly, it is possible to tell apart the KSZ8051 PHY from the
KSZ87xx switch by checking the Basic Status register Bit 0, which is
read-only and indicates presence of the Extended Capability Registers.
The KSZ8051 PHY has those registers while the KSZ87xx switch does not.

This patch implements simple check for the presence of this bit for
both the KSZ8051 PHY and KSZ87xx switch, to let both use the correct
PHY driver instance.

Fixes: 9d162ed69f51 ("net: phy: micrel: add support for KSZ8795")
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Andrew Lunn <andrew@lunn.ch>
Cc: David S. Miller <davem@davemloft.net>
Cc: Florian Fainelli <f.fainelli@gmail.com>
Cc: George McCollister <george.mccollister@gmail.com>
Cc: Heiner Kallweit <hkallweit1@gmail.com>
Cc: Sean Nyekjaer <sean.nyekjaer@prevas.dk>
Cc: Tristram Ha <Tristram.Ha@microchip.com>
Cc: Woojung Huh <woojung.huh@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Marek Vasut and committed by
David S. Miller
8b95599c 013572a2

+36 -4
+36 -4
drivers/net/phy/micrel.c
··· 341 341 return genphy_config_aneg(phydev); 342 342 } 343 343 344 + static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, 345 + const u32 ksz_phy_id) 346 + { 347 + int ret; 348 + 349 + if ((phydev->phy_id & MICREL_PHY_ID_MASK) != ksz_phy_id) 350 + return 0; 351 + 352 + ret = phy_read(phydev, MII_BMSR); 353 + if (ret < 0) 354 + return ret; 355 + 356 + /* KSZ8051 PHY and KSZ8794/KSZ8795/KSZ8765 switch share the same 357 + * exact PHY ID. However, they can be told apart by the extended 358 + * capability registers presence. The KSZ8051 PHY has them while 359 + * the switch does not. 360 + */ 361 + ret &= BMSR_ERCAP; 362 + if (ksz_phy_id == PHY_ID_KSZ8051) 363 + return ret; 364 + else 365 + return !ret; 366 + } 367 + 368 + static int ksz8051_match_phy_device(struct phy_device *phydev) 369 + { 370 + return ksz8051_ksz8795_match_phy_device(phydev, PHY_ID_KSZ8051); 371 + } 372 + 344 373 static int ksz8081_config_init(struct phy_device *phydev) 345 374 { 346 375 /* KSZPHY_OMSO_FACTORY_TEST is set at de-assertion of the reset line ··· 391 362 return ret; 392 363 393 364 return kszphy_config_init(phydev); 365 + } 366 + 367 + static int ksz8795_match_phy_device(struct phy_device *phydev) 368 + { 369 + return ksz8051_ksz8795_match_phy_device(phydev, PHY_ID_KSZ8795); 394 370 } 395 371 396 372 static int ksz9021_load_values_from_of(struct phy_device *phydev, ··· 1051 1017 .suspend = genphy_suspend, 1052 1018 .resume = genphy_resume, 1053 1019 }, { 1054 - .phy_id = PHY_ID_KSZ8051, 1055 - .phy_id_mask = MICREL_PHY_ID_MASK, 1056 1020 .name = "Micrel KSZ8051", 1057 1021 /* PHY_BASIC_FEATURES */ 1058 1022 .driver_data = &ksz8051_type, ··· 1061 1029 .get_sset_count = kszphy_get_sset_count, 1062 1030 .get_strings = kszphy_get_strings, 1063 1031 .get_stats = kszphy_get_stats, 1032 + .match_phy_device = ksz8051_match_phy_device, 1064 1033 .suspend = genphy_suspend, 1065 1034 .resume = genphy_resume, 1066 1035 }, { ··· 1174 1141 .suspend = genphy_suspend, 1175 1142 .resume = genphy_resume, 1176 1143 }, { 1177 - .phy_id = PHY_ID_KSZ8795, 1178 - .phy_id_mask = MICREL_PHY_ID_MASK, 1179 1144 .name = "Micrel KSZ8795", 1180 1145 /* PHY_BASIC_FEATURES */ 1181 1146 .config_init = kszphy_config_init, 1182 1147 .config_aneg = ksz8873mll_config_aneg, 1183 1148 .read_status = ksz8873mll_read_status, 1149 + .match_phy_device = ksz8795_match_phy_device, 1184 1150 .suspend = genphy_suspend, 1185 1151 .resume = genphy_resume, 1186 1152 }, {