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

net: phy: marvell10g: fix differentiation of 88X3310 from 88X3340

It seems that we cannot differentiate 88X3310 from 88X3340 by simply
looking at bit 3 of revision ID. This only works on revisions A0 and A1.
On revision B0, this bit is always 1.

Instead use the 3.d00d register for differentiation, since this register
contains information about number of ports on the device.

Fixes: 9885d016ffa9 ("net: phy: marvell10g: add separate structure for 88X3340")
Signed-off-by: Marek Behún <kabel@kernel.org>
Reported-by: Matteo Croce <mcroce@linux.microsoft.com>
Tested-by: Matteo Croce <mcroce@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Marek Behún and committed by
David S. Miller
a5de4be0 84f7e0bb

+36 -10
+35 -5
drivers/net/phy/marvell10g.c
··· 78 78 /* Temperature read register (88E2110 only) */ 79 79 MV_PCS_TEMP = 0x8042, 80 80 81 + /* Number of ports on the device */ 82 + MV_PCS_PORT_INFO = 0xd00d, 83 + MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380, 84 + MV_PCS_PORT_INFO_NPORTS_SHIFT = 7, 85 + 81 86 /* These registers appear at 0x800X and 0xa00X - the 0xa00X control 82 87 * registers appear to set themselves to the 0x800X when AN is 83 88 * restarted, but status registers appear readable from either. ··· 971 966 #endif 972 967 }; 973 968 969 + static int mv3310_get_number_of_ports(struct phy_device *phydev) 970 + { 971 + int ret; 972 + 973 + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PORT_INFO); 974 + if (ret < 0) 975 + return ret; 976 + 977 + ret &= MV_PCS_PORT_INFO_NPORTS_MASK; 978 + ret >>= MV_PCS_PORT_INFO_NPORTS_SHIFT; 979 + 980 + return ret + 1; 981 + } 982 + 983 + static int mv3310_match_phy_device(struct phy_device *phydev) 984 + { 985 + return mv3310_get_number_of_ports(phydev) == 1; 986 + } 987 + 988 + static int mv3340_match_phy_device(struct phy_device *phydev) 989 + { 990 + return mv3310_get_number_of_ports(phydev) == 4; 991 + } 992 + 974 993 static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) 975 994 { 976 995 int val; ··· 1023 994 static struct phy_driver mv3310_drivers[] = { 1024 995 { 1025 996 .phy_id = MARVELL_PHY_ID_88X3310, 1026 - .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, 997 + .phy_id_mask = MARVELL_PHY_ID_MASK, 998 + .match_phy_device = mv3310_match_phy_device, 1027 999 .name = "mv88x3310", 1028 1000 .driver_data = &mv3310_type, 1029 1001 .get_features = mv3310_get_features, ··· 1041 1011 .set_loopback = genphy_c45_loopback, 1042 1012 }, 1043 1013 { 1044 - .phy_id = MARVELL_PHY_ID_88X3340, 1045 - .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, 1014 + .phy_id = MARVELL_PHY_ID_88X3310, 1015 + .phy_id_mask = MARVELL_PHY_ID_MASK, 1016 + .match_phy_device = mv3340_match_phy_device, 1046 1017 .name = "mv88x3340", 1047 1018 .driver_data = &mv3340_type, 1048 1019 .get_features = mv3310_get_features, ··· 1100 1069 module_phy_driver(mv3310_drivers); 1101 1070 1102 1071 static struct mdio_device_id __maybe_unused mv3310_tbl[] = { 1103 - { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_88X33X0_MASK }, 1104 - { MARVELL_PHY_ID_88X3340, MARVELL_PHY_ID_88X33X0_MASK }, 1072 + { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK }, 1105 1073 { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK }, 1106 1074 { }, 1107 1075 };
+1 -5
include/linux/marvell_phy.h
··· 22 22 #define MARVELL_PHY_ID_88E1545 0x01410ea0 23 23 #define MARVELL_PHY_ID_88E1548P 0x01410ec0 24 24 #define MARVELL_PHY_ID_88E3016 0x01410e60 25 + #define MARVELL_PHY_ID_88X3310 0x002b09a0 25 26 #define MARVELL_PHY_ID_88E2110 0x002b09b0 26 27 #define MARVELL_PHY_ID_88X2222 0x01410f10 27 - 28 - /* PHY IDs and mask for Alaska 10G PHYs */ 29 - #define MARVELL_PHY_ID_88X33X0_MASK 0xfffffff8 30 - #define MARVELL_PHY_ID_88X3310 0x002b09a0 31 - #define MARVELL_PHY_ID_88X3340 0x002b09a8 32 28 33 29 /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ 34 30 #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0