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

net: phy: marvell: fix detection of PHY on Topaz switches

Since commit fee2d546414d ("net: phy: marvell: mv88e6390 temperature
sensor reading"), Linux reports the temperature of Topaz hwmon as
constant -75°C.

This is because switches from the Topaz family (88E6141 / 88E6341) have
the address of the temperature sensor register different from Peridot.

This address is instead compatible with 88E1510 PHYs, as was used for
Topaz before the above mentioned commit.

Create a new mapping table between switch family and PHY ID for families
which don't have a model number. And define PHY IDs for Topaz and Peridot
families.

Create a new PHY ID and a new PHY driver for Topaz's internal PHY.
The only difference from Peridot's PHY driver is the HWMON probing
method.

Prior this change Topaz's internal PHY is detected by kernel as:

PHY [...] driver [Marvell 88E6390] (irq=63)

And afterwards as:

PHY [...] driver [Marvell 88E6341 Family] (irq=63)

Signed-off-by: Pali Rohár <pali@kernel.org>
BugLink: https://github.com/globalscaletechnologies/linux/issues/1
Fixes: fee2d546414d ("net: phy: marvell: mv88e6390 temperature sensor reading")
Reviewed-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Pali Rohár and committed by
David S. Miller
1fe976d3 6628ddfe

+45 -22
+13 -17
drivers/net/dsa/mv88e6xxx/chip.c
··· 3026 3026 return err; 3027 3027 } 3028 3028 3029 + /* prod_id for switch families which do not have a PHY model number */ 3030 + static const u16 family_prod_id_table[] = { 3031 + [MV88E6XXX_FAMILY_6341] = MV88E6XXX_PORT_SWITCH_ID_PROD_6341, 3032 + [MV88E6XXX_FAMILY_6390] = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, 3033 + }; 3034 + 3029 3035 static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) 3030 3036 { 3031 3037 struct mv88e6xxx_mdio_bus *mdio_bus = bus->priv; 3032 3038 struct mv88e6xxx_chip *chip = mdio_bus->chip; 3039 + u16 prod_id; 3033 3040 u16 val; 3034 3041 int err; 3035 3042 ··· 3047 3040 err = chip->info->ops->phy_read(chip, bus, phy, reg, &val); 3048 3041 mv88e6xxx_reg_unlock(chip); 3049 3042 3050 - if (reg == MII_PHYSID2) { 3051 - /* Some internal PHYs don't have a model number. */ 3052 - if (chip->info->family != MV88E6XXX_FAMILY_6165) 3053 - /* Then there is the 6165 family. It gets is 3054 - * PHYs correct. But it can also have two 3055 - * SERDES interfaces in the PHY address 3056 - * space. And these don't have a model 3057 - * number. But they are not PHYs, so we don't 3058 - * want to give them something a PHY driver 3059 - * will recognise. 3060 - * 3061 - * Use the mv88e6390 family model number 3062 - * instead, for anything which really could be 3063 - * a PHY, 3064 - */ 3065 - if (!(val & 0x3f0)) 3066 - val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4; 3043 + /* Some internal PHYs don't have a model number. */ 3044 + if (reg == MII_PHYSID2 && !(val & 0x3f0) && 3045 + chip->info->family < ARRAY_SIZE(family_prod_id_table)) { 3046 + prod_id = family_prod_id_table[chip->info->family]; 3047 + if (prod_id) 3048 + val |= prod_id >> 4; 3067 3049 } 3068 3050 3069 3051 return err ? err : val;
+29 -3
drivers/net/phy/marvell.c
··· 3021 3021 .get_stats = marvell_get_stats, 3022 3022 }, 3023 3023 { 3024 - .phy_id = MARVELL_PHY_ID_88E6390, 3024 + .phy_id = MARVELL_PHY_ID_88E6341_FAMILY, 3025 3025 .phy_id_mask = MARVELL_PHY_ID_MASK, 3026 - .name = "Marvell 88E6390", 3026 + .name = "Marvell 88E6341 Family", 3027 + /* PHY_GBIT_FEATURES */ 3028 + .flags = PHY_POLL_CABLE_TEST, 3029 + .probe = m88e1510_probe, 3030 + .config_init = marvell_config_init, 3031 + .config_aneg = m88e6390_config_aneg, 3032 + .read_status = marvell_read_status, 3033 + .config_intr = marvell_config_intr, 3034 + .handle_interrupt = marvell_handle_interrupt, 3035 + .resume = genphy_resume, 3036 + .suspend = genphy_suspend, 3037 + .read_page = marvell_read_page, 3038 + .write_page = marvell_write_page, 3039 + .get_sset_count = marvell_get_sset_count, 3040 + .get_strings = marvell_get_strings, 3041 + .get_stats = marvell_get_stats, 3042 + .get_tunable = m88e1540_get_tunable, 3043 + .set_tunable = m88e1540_set_tunable, 3044 + .cable_test_start = marvell_vct7_cable_test_start, 3045 + .cable_test_tdr_start = marvell_vct5_cable_test_tdr_start, 3046 + .cable_test_get_status = marvell_vct7_cable_test_get_status, 3047 + }, 3048 + { 3049 + .phy_id = MARVELL_PHY_ID_88E6390_FAMILY, 3050 + .phy_id_mask = MARVELL_PHY_ID_MASK, 3051 + .name = "Marvell 88E6390 Family", 3027 3052 /* PHY_GBIT_FEATURES */ 3028 3053 .flags = PHY_POLL_CABLE_TEST, 3029 3054 .probe = m88e6390_probe, ··· 3132 3107 { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 3133 3108 { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 3134 3109 { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 3135 - { MARVELL_PHY_ID_88E6390, MARVELL_PHY_ID_MASK }, 3110 + { MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK }, 3111 + { MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK }, 3136 3112 { MARVELL_PHY_ID_88E1340S, MARVELL_PHY_ID_MASK }, 3137 3113 { MARVELL_PHY_ID_88E1548P, MARVELL_PHY_ID_MASK }, 3138 3114 { }
+3 -2
include/linux/marvell_phy.h
··· 28 28 /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ 29 29 #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 30 30 31 - /* The MV88e6390 Ethernet switch contains embedded PHYs. These PHYs do 31 + /* These Ethernet switch families contain embedded PHYs, but they do 32 32 * not have a model ID. So the switch driver traps reads to the ID2 33 33 * register and returns the switch family ID 34 34 */ 35 - #define MARVELL_PHY_ID_88E6390 0x01410f90 35 + #define MARVELL_PHY_ID_88E6341_FAMILY 0x01410f41 36 + #define MARVELL_PHY_ID_88E6390_FAMILY 0x01410f90 36 37 37 38 #define MARVELL_PHY_FAMILY_ID(id) ((id) >> 4) 38 39