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

net: phy: marvell: add support for MV88E6250 family internal PHYs

The embedded PHYs of the 88E6250 family switches are very basic - they
do not even have an Extended Address / Page register.

This adds support for the PHYs to the driver to set up PHY interrupts
and retrieve error stats. To deal with PHYs without a page register,
"simple" variants of all stat handling functions are introduced.

The code should work with all 88E6250 family switches (6250/6220/6071/
6070/6020). The PHY ID 0x01410db0 was read from a 88E6020, under the
assumption that all switches of this family use the same ID. The spec
only lists the prefix 0x01410c00 and leaves the last 10 bits as reserved,
but that seems too unspecific to be useful, as it would cover several
existing PHY IDs already supported by the driver; therefore, the ID read
from the actual hardware is used.

Signed-off-by: Matthias Schiffer <matthias.schiffer@ew.tq-group.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/0695f699cd942e6e06da9d30daeedfd47785bc01.1714643285.git.matthias.schiffer@ew.tq-group.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Matthias Schiffer and committed by
Jakub Kicinski
ecc2ae61 71dd027a

+82 -1
+80 -1
drivers/net/phy/marvell.c
··· 301 301 #define LPA_PAUSE_ASYM_FIBER 0x100 302 302 303 303 #define NB_FIBER_STATS 1 304 + #define NB_STAT_MAX 3 304 305 305 306 MODULE_DESCRIPTION("Marvell PHY driver"); 306 307 MODULE_AUTHOR("Andy Fleming"); ··· 320 319 { "phy_receive_errors_fiber", 1, 21, 16}, 321 320 }; 322 321 322 + static_assert(ARRAY_SIZE(marvell_hw_stats) <= NB_STAT_MAX); 323 + 324 + /* "simple" stat list + corresponding marvell_get_*_simple functions are used 325 + * on PHYs without a page register 326 + */ 327 + struct marvell_hw_stat_simple { 328 + const char *string; 329 + u8 reg; 330 + u8 bits; 331 + }; 332 + 333 + static const struct marvell_hw_stat_simple marvell_hw_stats_simple[] = { 334 + { "phy_receive_errors", 21, 16}, 335 + }; 336 + 337 + static_assert(ARRAY_SIZE(marvell_hw_stats_simple) <= NB_STAT_MAX); 338 + 323 339 enum { 324 340 M88E3082_VCT_OFF, 325 341 M88E3082_VCT_PHASE1, ··· 344 326 }; 345 327 346 328 struct marvell_priv { 347 - u64 stats[ARRAY_SIZE(marvell_hw_stats)]; 329 + u64 stats[NB_STAT_MAX]; 348 330 char *hwmon_name; 349 331 struct device *hwmon_dev; 350 332 bool cable_test_tdr; ··· 1996 1978 return ARRAY_SIZE(marvell_hw_stats) - NB_FIBER_STATS; 1997 1979 } 1998 1980 1981 + static int marvell_get_sset_count_simple(struct phy_device *phydev) 1982 + { 1983 + return ARRAY_SIZE(marvell_hw_stats_simple); 1984 + } 1985 + 1999 1986 static void marvell_get_strings(struct phy_device *phydev, u8 *data) 2000 1987 { 2001 1988 int count = marvell_get_sset_count(phydev); ··· 2009 1986 for (i = 0; i < count; i++) { 2010 1987 strscpy(data + i * ETH_GSTRING_LEN, 2011 1988 marvell_hw_stats[i].string, ETH_GSTRING_LEN); 1989 + } 1990 + } 1991 + 1992 + static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data) 1993 + { 1994 + int count = marvell_get_sset_count_simple(phydev); 1995 + int i; 1996 + 1997 + for (i = 0; i < count; i++) { 1998 + strscpy(data + i * ETH_GSTRING_LEN, 1999 + marvell_hw_stats_simple[i].string, ETH_GSTRING_LEN); 2012 2000 } 2013 2001 } 2014 2002 ··· 2042 2008 return ret; 2043 2009 } 2044 2010 2011 + static u64 marvell_get_stat_simple(struct phy_device *phydev, int i) 2012 + { 2013 + struct marvell_hw_stat_simple stat = marvell_hw_stats_simple[i]; 2014 + struct marvell_priv *priv = phydev->priv; 2015 + int val; 2016 + u64 ret; 2017 + 2018 + val = phy_read(phydev, stat.reg); 2019 + if (val < 0) { 2020 + ret = U64_MAX; 2021 + } else { 2022 + val = val & ((1 << stat.bits) - 1); 2023 + priv->stats[i] += val; 2024 + ret = priv->stats[i]; 2025 + } 2026 + 2027 + return ret; 2028 + } 2029 + 2045 2030 static void marvell_get_stats(struct phy_device *phydev, 2046 2031 struct ethtool_stats *stats, u64 *data) 2047 2032 { ··· 2069 2016 2070 2017 for (i = 0; i < count; i++) 2071 2018 data[i] = marvell_get_stat(phydev, i); 2019 + } 2020 + 2021 + static void marvell_get_stats_simple(struct phy_device *phydev, 2022 + struct ethtool_stats *stats, u64 *data) 2023 + { 2024 + int count = marvell_get_sset_count_simple(phydev); 2025 + int i; 2026 + 2027 + for (i = 0; i < count; i++) 2028 + data[i] = marvell_get_stat_simple(phydev, i); 2072 2029 } 2073 2030 2074 2031 static int m88e1510_loopback(struct phy_device *phydev, bool enable) ··· 3988 3925 .get_stats = marvell_get_stats, 3989 3926 }, 3990 3927 { 3928 + .phy_id = MARVELL_PHY_ID_88E6250_FAMILY, 3929 + .phy_id_mask = MARVELL_PHY_ID_MASK, 3930 + .name = "Marvell 88E6250 Family", 3931 + /* PHY_BASIC_FEATURES */ 3932 + .probe = marvell_probe, 3933 + .aneg_done = marvell_aneg_done, 3934 + .config_intr = marvell_config_intr, 3935 + .handle_interrupt = marvell_handle_interrupt, 3936 + .resume = genphy_resume, 3937 + .suspend = genphy_suspend, 3938 + .get_sset_count = marvell_get_sset_count_simple, 3939 + .get_strings = marvell_get_strings_simple, 3940 + .get_stats = marvell_get_stats_simple, 3941 + }, 3942 + { 3991 3943 .phy_id = MARVELL_PHY_ID_88E6341_FAMILY, 3992 3944 .phy_id_mask = MARVELL_PHY_ID_MASK, 3993 3945 .name = "Marvell 88E6341 Family", ··· 4150 4072 { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK }, 4151 4073 { MARVELL_PHY_ID_88E1545, MARVELL_PHY_ID_MASK }, 4152 4074 { MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK }, 4075 + { MARVELL_PHY_ID_88E6250_FAMILY, MARVELL_PHY_ID_MASK }, 4153 4076 { MARVELL_PHY_ID_88E6341_FAMILY, MARVELL_PHY_ID_MASK }, 4154 4077 { MARVELL_PHY_ID_88E6390_FAMILY, MARVELL_PHY_ID_MASK }, 4155 4078 { MARVELL_PHY_ID_88E6393_FAMILY, MARVELL_PHY_ID_MASK },
+2
include/linux/marvell_phy.h
··· 32 32 /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ 33 33 #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 34 34 35 + /* ID from 88E6020, assumed to be the same for the whole 6250 family */ 36 + #define MARVELL_PHY_ID_88E6250_FAMILY 0x01410db0 35 37 /* These Ethernet switch families contain embedded PHYs, but they do 36 38 * not have a model ID. So the switch driver traps reads to the ID2 37 39 * register and returns the switch family ID