[][kernel][common][eth][Fix 1G/2.5G RJ-45 SFP IOT issues]
[Description]
Fix 1G/2.5G SFP IOT issues.
- ADOP SFP-1GE-T-AD and SK-LiNK SFP-GE-T-100 1G RJ-45 SFP
The Marvell 88E1111 of the SFP does not report speed capabilities
from either BMSR or ESTATUS registers, utilize the feature callback
function of the PHY drvier instead.
- SK-LiNK SFP-GE-LX20-SM1310/SM1550-BIDI 1G Optical SFP
The EEPROM checksum value of the SFP is incorrect, print
warning messages to instead of returning error.
- 10Gtek ASF-2G2-T and TL-SM410U 2.5G RJ-45 SFP
The EEPROM of the SFP does not report speed capabilities, utilize
the quirk_list to report its.
[Release-log]
N/A
Change-Id: I8e732a98c5565e2192fbf0195eb9d23c5b952d1f
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7560882
diff --git a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
index c2acab2..3cc8f90 100755
--- a/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -440,22 +440,18 @@
sgm_mode = SGMII_IF_MODE_SGMII |
SGMII_REMOTE_FAULT_DIS |
SGMII_SPEED_DUPLEX_AN;
- } else if (phylink_autoneg_inband(mode)) {
- /* 1000base-X or HSGMII with autoneg */
- if (interface == PHY_INTERFACE_MODE_2500BASEX)
- return -EINVAL;
-
+ } else if (interface == PHY_INTERFACE_MODE_2500BASEX) {
+ /* HSGMII without autoneg */
+ speed = SGMII_SPEED_1000;
+ sgm_mode = SGMII_IF_MODE_SGMII;
+ } else {
+ /* 1000base-X with/without autoneg */
bmcr = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
advertising) ? SGMII_AN_ENABLE : 0;
if (bmcr)
sgm_mode = SGMII_SPEED_DUPLEX_AN;
else
speed = SGMII_SPEED_1000;
- } else {
- /* 1000base-X or HSGMII without autoneg */
- speed = SGMII_SPEED_1000;
- if (interface == PHY_INTERFACE_MODE_2500BASEX)
- sgm_mode = SGMII_IF_MODE_SGMII;
}
if (mpcs->interface != interface ||
diff --git a/target/linux/mediatek/mt7988/config-5.4 b/target/linux/mediatek/mt7988/config-5.4
index e706419..9906113 100644
--- a/target/linux/mediatek/mt7988/config-5.4
+++ b/target/linux/mediatek/mt7988/config-5.4
@@ -263,6 +263,7 @@
CONFIG_LZO_DECOMPRESS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_SERIAL=y
+CONFIG_MARVELL_PHY=y
CONFIG_MARVELL_10G_PHY=y
CONFIG_MAXLINEAR_GPHY=y
CONFIG_MD=y
diff --git a/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch b/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
index 5a6e865..5841992 100644
--- a/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
+++ b/target/linux/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
@@ -601,7 +601,18 @@
/**
* sfp_parse_port() - Parse the EEPROM base ID, setting the port type
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
-@@ -359,7 +272,7 @@ void sfp_parse_support(struct sfp_bus *b
+@@ -236,6 +149,10 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
+ unsigned int br_min, br_nom, br_max;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
+
++ phylink_set(modes, Autoneg);
++ phylink_set(modes, Pause);
++ phylink_set(modes, Asym_Pause);
++
+ /* Decode the bitrate information to MBd */
+ br_min = br_nom = br_max = 0;
+ if (id->base.br_nominal) {
+@@ -359,14 +276,10 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
phylink_set(modes, 1000baseX_Full);
}
@@ -610,6 +621,13 @@
bus->sfp_quirk->modes(id, modes);
bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
+-
+- phylink_set(support, Autoneg);
+- phylink_set(support, Pause);
+- phylink_set(support, Asym_Pause);
+ }
+ EXPORT_SYMBOL_GPL(sfp_parse_support);
+
@@ -737,12 +650,13 @@ void sfp_link_down(struct sfp_bus *bus)
}
EXPORT_SYMBOL_GPL(sfp_link_down);
@@ -626,9 +644,11 @@
if (ops && ops->module_insert)
ret = ops->module_insert(bus->upstream, id);
+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
+index f8d1742..4d07752 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
-@@ -165,6 +165,7 @@ static const enum gpiod_flags gpio_flags
+@@ -165,6 +165,7 @@ static const enum gpiod_flags gpio_flags[] = {
* on board (for a copper SFP) time to initialise.
*/
#define T_WAIT msecs_to_jiffies(50)
@@ -636,7 +656,7 @@
#define T_START_UP msecs_to_jiffies(300)
#define T_START_UP_BAD_GPON msecs_to_jiffies(60000)
-@@ -204,8 +205,11 @@ static const enum gpiod_flags gpio_flags
+@@ -204,8 +205,11 @@ static const enum gpiod_flags gpio_flags[] = {
/* SFP modules appear to always have their PHY configured for bus address
* 0x56 (which with mdio-i2c, translates to a PHY address of 22).
@@ -676,7 +696,26 @@
#if IS_ENABLED(CONFIG_HWMON)
struct sfp_diag diag;
-@@ -303,6 +313,156 @@ static const struct of_device_id sfp_of_
+@@ -287,6 +297,18 @@ static bool sfp_module_supported(const struct sfp_eeprom_id *id)
+ !memcmp(id->base.vendor_pn, "UF-INSTANT ", 16))
+ return true;
+
++ /* SFP GPON module SK-LiNK SFP-GE-LX20 SM1310 and SM1550 Instant
++ * has in its EEPROM stored phys id UNK instead of SFP. Therefore
++ * mark this module explicitly as supported based on vendor name
++ * and pn match.
++ */
++ if (id->base.phys_id == SFF8024_ID_UNK &&
++ id->base.phys_ext_id == SFP_PHYS_EXT_ID_SFP &&
++ !memcmp(id->base.vendor_name, "SK-LINK ", 16) &&
++ (!memcmp(id->base.vendor_pn, "SFP-GE-LX20-SM13", 16) ||
++ !memcmp(id->base.vendor_pn, "SFP-GE-LX-SM1550", 16)))
++ return true;
++
+ return false;
+ }
+
+@@ -303,6 +334,180 @@ static const struct of_device_id sfp_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sfp_of_match);
@@ -732,6 +771,21 @@
+ linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, modes);
+}
+
++static void sfp_quirk_disable_autoneg(const struct sfp_eeprom_id *id,
++ unsigned long *modes)
++{
++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, modes);
++}
++
++static void sfp_quirk_oem_2_5g(const struct sfp_eeprom_id *id,
++ unsigned long *modes)
++{
++ /* Copper 2.5G SFP */
++ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, modes);
++ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes);
++ sfp_quirk_disable_autoneg(id, modes);
++}
++
+static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
+ unsigned long *modes)
+{
@@ -773,10 +827,19 @@
+ // 2500MBd NRZ in their EEPROM
+ SFP_QUIRK_M("Lantech", "8330-262D-E", '\0', sfp_quirk_2500basex),
+
++ // CISCO PLRXPL-VC-S43-CG can operate at 10000baseSR, but not report
++ // in their EEPROM
+ SFP_QUIRK_M("CISCO-JDSU", "PLRXPL-VC-S43-CG", '\0', sfp_quirk_10000baseSR),
+
+ SFP_QUIRK_M("UBNT", "UF-INSTANT", '\0', sfp_quirk_ubnt_uf_instant),
+
++ // OEM SFP-2.5G-T can operate at 2500base-T, but not report
++ // in their EEPROM
++ SFP_QUIRK_M("OEM", "SFP-2.5G-T", '\0', sfp_quirk_oem_2_5g),
++ // TP-LINK TL-SM410U can operate at 2500base-T, but not report
++ // in their EEPROM
++ SFP_QUIRK_M("TP-LINK", "TL-SM410U", '\0', sfp_quirk_oem_2_5g),
++
+ SFP_QUIRK_F("ETU", "ESP-T5-R", '\0', sfp_fixup_rollball_cc),
+ SFP_QUIRK_F("OEM", "SFP-10G-T", '\0', sfp_fixup_rollball_cc),
+ SFP_QUIRK_F("OEM", "RTSFP-10", '\0', sfp_fixup_rollball_cc),
@@ -833,7 +896,7 @@
static unsigned long poll_jiffies;
static unsigned int sfp_gpio_get_state(struct sfp *sfp)
-@@ -414,9 +554,6 @@ static int sfp_i2c_write(struct sfp *sfp
+@@ -414,9 +619,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
{
@@ -843,7 +906,7 @@
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
return -EINVAL;
-@@ -424,7 +561,15 @@ static int sfp_i2c_configure(struct sfp
+@@ -424,7 +626,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
sfp->read = sfp_i2c_read;
sfp->write = sfp_i2c_write;
@@ -860,7 +923,7 @@
if (IS_ERR(i2c_mii))
return PTR_ERR(i2c_mii);
-@@ -442,6 +587,12 @@ static int sfp_i2c_configure(struct sfp
+@@ -442,6 +652,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
return 0;
}
@@ -873,7 +936,7 @@
/* Interface */
static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
{
-@@ -487,17 +638,18 @@ static void sfp_soft_set_state(struct sf
+@@ -487,17 +703,18 @@ static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
static void sfp_soft_start_poll(struct sfp *sfp)
{
const struct sfp_eeprom_id *id = &sfp->id;
@@ -901,7 +964,7 @@
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
!sfp->need_poll)
-@@ -511,10 +663,11 @@ static void sfp_soft_stop_poll(struct sf
+@@ -511,10 +728,11 @@ static void sfp_soft_stop_poll(struct sfp *sfp)
static unsigned int sfp_get_state(struct sfp *sfp)
{
@@ -916,7 +979,7 @@
state |= sfp_soft_get_state(sfp);
return state;
-@@ -1448,12 +1601,12 @@ static void sfp_sm_phy_detach(struct sfp
+@@ -1448,12 +1666,12 @@ static void sfp_sm_phy_detach(struct sfp *sfp)
sfp->mod_phy = NULL;
}
@@ -931,7 +994,7 @@
if (phy == ERR_PTR(-ENODEV))
return PTR_ERR(phy);
if (IS_ERR(phy)) {
-@@ -1548,6 +1701,14 @@ static void sfp_sm_fault(struct sfp *sfp
+@@ -1548,6 +1766,14 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
}
}
@@ -946,7 +1009,7 @@
/* Probe a SFP for a PHY device if the module supports copper - the PHY
* normally sits at I2C bus address 0x56, and may either be a clause 22
* or clause 45 PHY.
-@@ -1563,19 +1724,23 @@ static int sfp_sm_probe_for_phy(struct s
+@@ -1563,36 +1789,52 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
{
int err = 0;
@@ -979,7 +1042,6 @@
return err;
}
-@@ -1755,17 +1783,29 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
static int sfp_module_parse_power(struct sfp *sfp)
{
u32 power_mW = 1000;
@@ -1014,7 +1076,7 @@
/* The module appears not to implement bus address
* 0xa2, so assume that the module powers up in the
* indicated mode.
-@@ -1782,13 +1822,21 @@ static int sfp_module_parse_power(struct sfp *sfp)
+@@ -1609,13 +1851,21 @@ static int sfp_module_parse_power(struct sfp *sfp)
}
}
@@ -1038,7 +1100,34 @@
power_mW / 1000, (power_mW / 100) % 10);
return 0;
}
-@@ -1819,11 +1984,33 @@ static int sfp_sm_mod_probe(struct sfp *
+@@ -1692,7 +1942,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
+ {
+ /* SFP module inserted - read I2C data */
+ struct sfp_eeprom_id id;
+- bool cotsworks;
++ bool cotsworks, sklink;
+ u8 check;
+ int ret;
+
+@@ -1747,10 +1997,16 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
+ */
+ cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS ", 16);
+
++ /* SK-LiNK do not seem to update the checksums when they
++ * do the final programming with the final module part number,
++ * serial number and date code.
++ */
++ sklink = !memcmp(id.base.vendor_name, "SK-LINK ", 16);
++
+ /* Validate the checksum over the base structure */
+ check = sfp_check(&id.base, sizeof(id.base) - 1);
+ if (check != id.base.cc_base) {
+- if (cotsworks) {
++ if (cotsworks || sklink) {
+ dev_warn(sfp->dev,
+ "EEPROM base structure checksum failure (0x%02x != 0x%02x)\n",
+ check, id.base.cc_base);
+@@ -1819,11 +2075,33 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
if (ret < 0)
return ret;
@@ -1076,7 +1165,7 @@
return 0;
}
-@@ -1936,7 +2123,8 @@ static void sfp_sm_module(struct sfp *sf
+@@ -1936,7 +2214,8 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
break;
/* Report the module insertion to the upstream device */
@@ -1086,7 +1175,7 @@
if (err < 0) {
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
break;
-@@ -1995,6 +2183,8 @@ static void sfp_sm_main(struct sfp *sfp,
+@@ -1995,6 +2274,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
sfp_module_stop(sfp->sfp_bus);
if (sfp->mod_phy)
sfp_sm_phy_detach(sfp);
@@ -1095,7 +1184,7 @@
sfp_module_tx_disable(sfp);
sfp_soft_stop_poll(sfp);
sfp_sm_next(sfp, SFP_S_DOWN, 0);
-@@ -2018,9 +2208,10 @@ static void sfp_sm_main(struct sfp *sfp,
+@@ -2018,9 +2299,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
/* We need to check the TX_FAULT state, which is not defined
* while TX_DISABLE is asserted. The earliest we want to do
@@ -1108,7 +1197,7 @@
break;
case SFP_S_WAIT:
-@@ -2034,8 +2225,8 @@ static void sfp_sm_main(struct sfp *sfp,
+@@ -2034,8 +2316,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
* deasserting.
*/
timeout = sfp->module_t_start_up;
@@ -1119,7 +1208,7 @@
else
timeout = 1;
-@@ -2057,6 +2248,12 @@ static void sfp_sm_main(struct sfp *sfp,
+@@ -2057,6 +2339,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
sfp->sm_fault_retries == N_FAULT_INIT);
} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
init_done:
@@ -1132,7 +1221,7 @@
sfp->sm_phy_retries = R_PHY_RETRY;
goto phy_probe;
}
-@@ -2409,6 +2606,8 @@ static int sfp_probe(struct platform_dev
+@@ -2409,6 +2697,8 @@ static int sfp_probe(struct platform_device *pdev)
return PTR_ERR(sfp->gpio[i]);
}
@@ -1168,6 +1257,17 @@
void sfp_module_remove(struct sfp_bus *bus);
int sfp_module_start(struct sfp_bus *bus);
void sfp_module_stop(struct sfp_bus *bus);
+ --- a/drivers/net/phy/marvell.c
++++ b/drivers/net/phy/marvell.c
+@@ -2175,7 +2175,7 @@ static struct phy_driver marvell_drivers[] = {
+ .phy_id = MARVELL_PHY_ID_88E1111,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E1111",
+- /* PHY_GBIT_FEATURES */
++ .features = PHY_GBIT_FEATURES,
+ .probe = marvell_probe,
+ .config_init = &m88e1111_config_init,
+ .config_aneg = &marvell_config_aneg,
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -32,6 +32,15 @@