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

net: phy: marvell: add special handling of Finisar modules with 88E1111

The Finisar FCLF8520P2BTL 1000BaseT SFP module uses a Marvel 88E1111 PHY
with a modified PHY ID. Add support for this ID using the 88E1111
methods.

By default these modules do not have 1000BaseX auto-negotiation enabled,
which is not generally desirable with Linux networking drivers. Add
handling to enable 1000BaseX auto-negotiation when these modules are
used in 1000BaseX mode. Also, some special handling is required to ensure
that 1000BaseT auto-negotiation is enabled properly when desired.

Based on existing handling in the AMD xgbe driver and the information in
the Finisar FAQ:
https://www.finisar.com/sites/default/files/resources/an-2036_1000base-t_sfp_faqreve1.pdf

Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Reviewed-by: Russell King <rmk+kernel@armlinux.org.uk>
Link: https://lore.kernel.org/r/20201028171540.1700032-1-robert.hancock@calian.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Robert Hancock and committed by
Jakub Kicinski
1887023a be25f43a

+102 -1
+99 -1
drivers/net/phy/marvell.c
··· 80 80 #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 81 81 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 82 82 #define MII_M1111_HWCFG_MODE_RTBI 0x7 83 + #define MII_M1111_HWCFG_MODE_COPPER_1000X_AN 0x8 83 84 #define MII_M1111_HWCFG_MODE_COPPER_RTBI 0x9 84 85 #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb 86 + #define MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN 0xc 87 + #define MII_M1111_HWCFG_SERIAL_AN_BYPASS BIT(12) 85 88 #define MII_M1111_HWCFG_FIBER_COPPER_RES BIT(13) 86 89 #define MII_M1111_HWCFG_FIBER_COPPER_AUTO BIT(15) 87 90 ··· 632 629 return genphy_check_and_restart_aneg(phydev, changed); 633 630 } 634 631 632 + static int m88e1111_config_aneg(struct phy_device *phydev) 633 + { 634 + int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); 635 + int err; 636 + 637 + if (extsr < 0) 638 + return extsr; 639 + 640 + /* If not using SGMII or copper 1000BaseX modes, use normal process. 641 + * Steps below are only required for these modes. 642 + */ 643 + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && 644 + (extsr & MII_M1111_HWCFG_MODE_MASK) != 645 + MII_M1111_HWCFG_MODE_COPPER_1000X_AN) 646 + return marvell_config_aneg(phydev); 647 + 648 + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 649 + if (err < 0) 650 + goto error; 651 + 652 + /* Configure the copper link first */ 653 + err = marvell_config_aneg(phydev); 654 + if (err < 0) 655 + goto error; 656 + 657 + /* Do not touch the fiber page if we're in copper->sgmii mode */ 658 + if (phydev->interface == PHY_INTERFACE_MODE_SGMII) 659 + return 0; 660 + 661 + /* Then the fiber link */ 662 + err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE); 663 + if (err < 0) 664 + goto error; 665 + 666 + err = marvell_config_aneg_fiber(phydev); 667 + if (err < 0) 668 + goto error; 669 + 670 + return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 671 + 672 + error: 673 + marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); 674 + return err; 675 + } 676 + 635 677 static int m88e1510_config_aneg(struct phy_device *phydev) 636 678 { 637 679 int err; ··· 862 814 MII_M1111_HWCFG_FIBER_COPPER_AUTO); 863 815 } 864 816 817 + static int m88e1111_config_init_1000basex(struct phy_device *phydev) 818 + { 819 + int extsr = phy_read(phydev, MII_M1111_PHY_EXT_SR); 820 + int err, mode; 821 + 822 + if (extsr < 0) 823 + return extsr; 824 + 825 + /* If using copper mode, ensure 1000BaseX auto-negotiation is enabled */ 826 + mode = extsr & MII_M1111_HWCFG_MODE_MASK; 827 + if (mode == MII_M1111_HWCFG_MODE_COPPER_1000X_NOAN) { 828 + err = phy_modify(phydev, MII_M1111_PHY_EXT_SR, 829 + MII_M1111_HWCFG_MODE_MASK | 830 + MII_M1111_HWCFG_SERIAL_AN_BYPASS, 831 + MII_M1111_HWCFG_MODE_COPPER_1000X_AN | 832 + MII_M1111_HWCFG_SERIAL_AN_BYPASS); 833 + if (err < 0) 834 + return err; 835 + } 836 + return 0; 837 + } 838 + 865 839 static int m88e1111_config_init(struct phy_device *phydev) 866 840 { 867 841 int err; ··· 902 832 903 833 if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { 904 834 err = m88e1111_config_init_rtbi(phydev); 835 + if (err < 0) 836 + return err; 837 + } 838 + 839 + if (phydev->interface == PHY_INTERFACE_MODE_1000BASEX) { 840 + err = m88e1111_config_init_1000basex(phydev); 905 841 if (err < 0) 906 842 return err; 907 843 } ··· 2734 2658 /* PHY_GBIT_FEATURES */ 2735 2659 .probe = marvell_probe, 2736 2660 .config_init = m88e1111_config_init, 2737 - .config_aneg = marvell_config_aneg, 2661 + .config_aneg = m88e1111_config_aneg, 2662 + .read_status = marvell_read_status, 2663 + .ack_interrupt = marvell_ack_interrupt, 2664 + .config_intr = marvell_config_intr, 2665 + .resume = genphy_resume, 2666 + .suspend = genphy_suspend, 2667 + .read_page = marvell_read_page, 2668 + .write_page = marvell_write_page, 2669 + .get_sset_count = marvell_get_sset_count, 2670 + .get_strings = marvell_get_strings, 2671 + .get_stats = marvell_get_stats, 2672 + .get_tunable = m88e1111_get_tunable, 2673 + .set_tunable = m88e1111_set_tunable, 2674 + }, 2675 + { 2676 + .phy_id = MARVELL_PHY_ID_88E1111_FINISAR, 2677 + .phy_id_mask = MARVELL_PHY_ID_MASK, 2678 + .name = "Marvell 88E1111 (Finisar)", 2679 + /* PHY_GBIT_FEATURES */ 2680 + .probe = marvell_probe, 2681 + .config_init = m88e1111_config_init, 2682 + .config_aneg = m88e1111_config_aneg, 2738 2683 .read_status = marvell_read_status, 2739 2684 .ack_interrupt = marvell_ack_interrupt, 2740 2685 .config_intr = marvell_config_intr, ··· 3086 2989 { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK }, 3087 2990 { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK }, 3088 2991 { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK }, 2992 + { MARVELL_PHY_ID_88E1111_FINISAR, MARVELL_PHY_ID_MASK }, 3089 2993 { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK }, 3090 2994 { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK }, 3091 2995 { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
+3
include/linux/marvell_phy.h
··· 25 25 #define MARVELL_PHY_ID_88X3310 0x002b09a0 26 26 #define MARVELL_PHY_ID_88E2110 0x002b09b0 27 27 28 + /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ 29 + #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 30 + 28 31 /* The MV88e6390 Ethernet switch contains embedded PHYs. These PHYs do 29 32 * not have a model ID. So the switch driver traps reads to the ID2 30 33 * register and returns the switch family ID