[][kernel][common][eth][Add debug information to the SFP]
[Description]
Add debug information to the SFP.
In this patch, we provide the following information to assist
users in easily locating issues.
- Dump SFP state machine
- Dump System/Line interface status
- Dump SFP, PHY, and Host link mode
If debug messages is too annoying, user can disable it by "dmesg -n 7"
command.
Without this patch, users cannot locate SFP issues easily.
[Release-log]
N/A
Change-Id: I567ed96bfb489cecb1887cd08518d01a7ed33657
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7714996
diff --git a/target/linux/mediatek/patches-5.4/999-2727-net-phy-sfp-add-debug-info.patch.patch b/target/linux/mediatek/patches-5.4/999-2727-net-phy-sfp-add-debug-info.patch.patch
new file mode 100644
index 0000000..593ddb1
--- /dev/null
+++ b/target/linux/mediatek/patches-5.4/999-2727-net-phy-sfp-add-debug-info.patch.patch
@@ -0,0 +1,211 @@
+From 76314e98504e691f17a5d9d1362d476c534a5e0e Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Fri, 7 Jul 2023 11:14:32 +0800
+Subject: [PATCH] 999-2727-net-phy-sfp-add-debug-info.patch
+
+---
+ drivers/net/phy/phylink.c | 11 +++++++-
+ drivers/net/phy/sfp-bus.c | 3 +++
+ drivers/net/phy/sfp.c | 51 +++++++++++++++++++++++++++++------
+ include/linux/mdio/mdio-i2c.h | 16 +++++++++++
+ 4 files changed, 72 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index 949e3b8..bb4cd28 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -782,6 +782,15 @@ static void phylink_resolve(struct work_struct *w)
+ &link_state);
+ }
+
++ if (pl->phydev && !(link_state.link & pl->phy_state.link))
++ phylink_printk(KERN_DEBUG, pl,
++ "resolve link status: system iface=%d, line iface=%d\n",
++ link_state.link, pl->phy_state.link);
++ else if (!link_state.link)
++ phylink_printk(KERN_DEBUG, pl,
++ "resolve link status: system iface=%d\n",
++ link_state.link);
++
+ /* If we have a phy, the "up" state is the union of
+ * both the PHY and the MAC
+ */
+@@ -2084,7 +2093,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
+ return ret;
+ }
+
+- phylink_dbg(pl, "requesting link mode %s/%s with support %*pb\n",
++ phylink_info(pl, "requesting link mode %s/%s with support %*pb\n",
+ phylink_an_mode_str(mode), phy_modes(config.interface),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, support);
+
+diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
+index 4be2440..bcf45dd 100644
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -279,6 +279,9 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
+ if (bus->sfp_quirk && bus->sfp_quirk->modes)
+ bus->sfp_quirk->modes(id, modes);
+
++ dev_info(bus->sfp_dev, "sfp: support mode %*pb\n",
++ __ETHTOOL_LINK_MODE_MASK_NBITS, modes);
++
+ bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ }
+ EXPORT_SYMBOL_GPL(sfp_parse_support);
+diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
+index 0fdf5d6..0c335b1 100644
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -480,7 +480,7 @@ static bool sfp_match(const char *qs, const char *str, size_t len)
+ return !strncmp(qs, str, len);
+ }
+
+-static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
++static const struct sfp_quirk *sfp_lookup_quirk(struct sfp *sfp, const struct sfp_eeprom_id *id)
+ {
+ const struct sfp_quirk *q;
+ unsigned int i;
+@@ -493,8 +493,14 @@ static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
+ for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
+ if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
+ sfp_match(q->part, id->base.vendor_pn, ps) &&
+- sfp_match(q->revision, id->base.vendor_rev, rs))
++ sfp_match(q->revision, id->base.vendor_rev, rs)) {
++ dev_info(sfp->dev,
++ "module %.*s %.*s rev %.*s has been found in the quirk list\n",
++ (int)sizeof(id->base.vendor_name), id->base.vendor_name,
++ (int)sizeof(id->base.vendor_pn), id->base.vendor_pn,
++ (int)sizeof(id->base.vendor_rev), id->base.vendor_rev);
+ return q;
++ }
+
+ return NULL;
+ }
+@@ -1597,7 +1603,7 @@ static void sfp_hwmon_exit(struct sfp *sfp)
+ /* Helpers */
+ static void sfp_module_tx_disable(struct sfp *sfp)
+ {
+- dev_dbg(sfp->dev, "tx disable %u -> %u\n",
++ dev_info(sfp->dev, "tx disable %u -> %u\n",
+ sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1);
+ sfp->state |= SFP_F_TX_DISABLE;
+ sfp_set_state(sfp, sfp->state);
+@@ -1605,7 +1611,7 @@ static void sfp_module_tx_disable(struct sfp *sfp)
+
+ static void sfp_module_tx_enable(struct sfp *sfp)
+ {
+- dev_dbg(sfp->dev, "tx disable %u -> %u\n",
++ dev_info(sfp->dev, "tx disable %u -> %u\n",
+ sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0);
+ sfp->state &= ~SFP_F_TX_DISABLE;
+ sfp_set_state(sfp, sfp->state);
+@@ -1660,7 +1666,8 @@ static void sfp_sm_phy_detach(struct sfp *sfp)
+ static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
+ {
+ struct phy_device *phy;
+- int err;
++ int err, i;
++ u32 id;
+
+ phy = get_phy_device(sfp->i2c_mii, addr, is_c45);
+ if (phy == ERR_PTR(-ENODEV))
+@@ -1677,6 +1684,30 @@ static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
+ return err;
+ }
+
++ if (phy->is_c45) {
++ for (i = 0; i < ARRAY_SIZE(phy->c45_ids.device_ids); i++) {
++ id = phy->c45_ids.device_ids[i];
++ if (id == 0xffffffff)
++ continue;
++
++ dev_info(sfp->dev,
++ "CL45 PHY device [0x%04x:0x%04x] found!\n",
++ (id >> 16) & 0xffff, id & 0xffff);
++ }
++ } else {
++ id = phy->phy_id;
++ dev_info(sfp->dev,
++ "CL22 PHY device [0x%04x:0x%04x] found!\n",
++ (id >> 16) & 0xffff, id & 0xffff);
++ }
++
++ dev_info(sfp->dev, "CL%s PHY driver [%s] found!\n",
++ phy->is_c45 ? "45" : "22",
++ phy->drv ? phy->drv->name : "not");
++
++ dev_info(sfp->dev, "phy: support mode %*pb\n",
++ __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported);
++
+ err = sfp_add_phy(sfp->sfp_bus, phy);
+ if (err) {
+ phy_device_remove(phy);
+@@ -1779,6 +1810,10 @@ static int sfp_sm_add_mdio_bus(struct sfp *sfp)
+ static int sfp_sm_probe_for_phy(struct sfp *sfp)
+ {
+ int err = 0;
++ struct phy_device *phy;
++
++ dev_info(sfp->dev, "probing phy device through the [%s] protocol\n",
++ mdio_i2c_proto_type(sfp->mdio_protocol));
+
+ switch (sfp->mdio_protocol) {
+ case MDIO_I2C_NONE:
+@@ -2090,7 +2125,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
+ else
+ sfp->mdio_protocol = MDIO_I2C_NONE;
+
+- sfp->quirk = sfp_lookup_quirk(&id);
++ sfp->quirk = sfp_lookup_quirk(sfp, &id);
+ if (sfp->quirk && sfp->quirk->fixup)
+ sfp->quirk->fixup(sfp);
+
+@@ -2419,7 +2454,7 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
+ {
+ mutex_lock(&sfp->sm_mutex);
+
+- dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
++ dev_info(sfp->dev, "SM: enter %s:%s:%s event %s\n",
+ mod_state_to_str(sfp->sm_mod_state),
+ dev_state_to_str(sfp->sm_dev_state),
+ sm_state_to_str(sfp->sm_state),
+@@ -2429,7 +2464,7 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
+ sfp_sm_module(sfp, event);
+ sfp_sm_main(sfp, event);
+
+- dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
++ dev_info(sfp->dev, "SM: exit %s:%s:%s\n",
+ mod_state_to_str(sfp->sm_mod_state),
+ dev_state_to_str(sfp->sm_dev_state),
+ sm_state_to_str(sfp->sm_state));
+diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h
+index 1c21140..4bf833d 100644
+--- a/include/linux/mdio/mdio-i2c.h
++++ b/include/linux/mdio/mdio-i2c.h
+@@ -18,6 +18,22 @@ enum mdio_i2c_proto {
+ MDIO_I2C_ROLLBALL,
+ };
+
++static inline const char *mdio_i2c_proto_type(int type)
++{
++ switch (type) {
++ case MDIO_I2C_NONE:
++ return "MDIO_I2C_NONE";
++ case MDIO_I2C_MARVELL_C22:
++ return "MDIO_I2C_MARVELL_C22";
++ case MDIO_I2C_C45:
++ return "MDIO_I2C_C45";
++ case MDIO_I2C_ROLLBALL:
++ return "MDIO_I2C_ROLLBALL";
++ default:
++ return "UNKNOWN";
++ }
++}
++
+ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
+ enum mdio_i2c_proto protocol);
+
+--
+2.18.0
+