]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bnxt_en: Implement ethtool_ops -> get_link_ext_state()
authorMichael Chan <michael.chan@broadcom.com>
Thu, 8 Jan 2026 18:35:21 +0000 (10:35 -0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 10 Jan 2026 23:19:51 +0000 (15:19 -0800)
Map the link_down_reason from the FW to the ethtool link_ext_state
when it is available.  Also log it to the link down dmesg when it is
available.  Add 2 new link_ext_state enums to the UAPI:

ETHTOOL_LINK_EXT_STATE_OTP_SPEED_VIOLATION
ETHTOOL_LINK_EXT_STATE_BMC_REQUEST_DOWN

to cover OTP (one-time-programmable) speed restrictions and
BMC (Baseboard management controller) forcing the link down.

Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20260108183521.215610-7-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
include/uapi/linux/ethtool.h

index 9902babd82cb0f9714de3a84654ab127eac34d11..cb78614d4108104541ea15ec876294f2cff83076 100644 (file)
@@ -11915,6 +11915,26 @@ static char *bnxt_report_fec(struct bnxt_link_info *link_info)
        }
 }
 
+static char *bnxt_link_down_reason(struct bnxt_link_info *link_info)
+{
+       u8 reason = link_info->link_down_reason;
+
+       /* Multiple bits can be set, we report 1 bit only in order of
+        * priority.
+        */
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF)
+               return "(Remote fault)";
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_OTP_SPEED_VIOLATION)
+               return "(OTP Speed limit violation)";
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_CABLE_REMOVED)
+               return "(Cable removed)";
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_MODULE_FAULT)
+               return "(Module fault)";
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_BMC_REQUEST)
+               return "(BMC request down)";
+       return "";
+}
+
 void bnxt_report_link(struct bnxt *bp)
 {
        if (BNXT_LINK_IS_UP(bp)) {
@@ -11972,8 +11992,10 @@ void bnxt_report_link(struct bnxt *bp)
                                    (fec & BNXT_FEC_AUTONEG) ? "on" : "off",
                                    bnxt_report_fec(&bp->link_info));
        } else {
+               char *str = bnxt_link_down_reason(&bp->link_info);
+
                netif_carrier_off(bp->dev);
-               netdev_err(bp->dev, "NIC Link is Down\n");
+               netdev_err(bp->dev, "NIC Link is Down %s\n", str);
        }
 }
 
@@ -12173,6 +12195,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
        link_info->phy_addr = resp->eee_config_phy_addr &
                              PORT_PHY_QCFG_RESP_PHY_ADDR_MASK;
        link_info->module_status = resp->module_status;
+       link_info->link_down_reason = resp->link_down_reason;
 
        if (bp->phy_flags & BNXT_PHY_FL_EEE_CAP) {
                struct ethtool_keee *eee = &bp->eee;
index 3afd1d5e364a580f4bf64de3e2a373a3337b9fb8..e441a002ddefddd75d4dabfd64f665f71c6841df 100644 (file)
@@ -1553,6 +1553,7 @@ struct bnxt_link_info {
 #define BNXT_LINK_STATE_DOWN   1
 #define BNXT_LINK_STATE_UP     2
 #define BNXT_LINK_IS_UP(bp)    ((bp)->link_info.link_state == BNXT_LINK_STATE_UP)
+       u8                      link_down_reason;
        u8                      active_lanes;
        u8                      duplex;
 #define BNXT_LINK_DUPLEX_HALF  PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF
index 4dfae7b61c76a94251b03154dbb3104c158228a3..6b15fedbb16f687040fc285acd85a0f04ce96d8f 100644 (file)
@@ -3432,6 +3432,40 @@ static u32 bnxt_get_link(struct net_device *dev)
        return BNXT_LINK_IS_UP(bp);
 }
 
+static int bnxt_get_link_ext_state(struct net_device *dev,
+                                  struct ethtool_link_ext_state_info *info)
+{
+       struct bnxt *bp = netdev_priv(dev);
+       u8 reason;
+
+       if (BNXT_LINK_IS_UP(bp))
+               return -ENODATA;
+
+       reason = bp->link_info.link_down_reason;
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF) {
+               info->link_ext_state = ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE;
+               info->link_training = ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT;
+               return 0;
+       }
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_CABLE_REMOVED) {
+               info->link_ext_state = ETHTOOL_LINK_EXT_STATE_NO_CABLE;
+               return 0;
+       }
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_OTP_SPEED_VIOLATION) {
+               info->link_ext_state = ETHTOOL_LINK_EXT_STATE_OTP_SPEED_VIOLATION;
+               return 0;
+       }
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_MODULE_FAULT) {
+               info->link_ext_state = ETHTOOL_LINK_EXT_STATE_MODULE;
+               return 0;
+       }
+       if (reason & PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_BMC_REQUEST) {
+               info->link_ext_state = ETHTOOL_LINK_EXT_STATE_BMC_REQUEST_DOWN;
+               return 0;
+       }
+       return -ENODATA;
+}
+
 int bnxt_hwrm_nvm_get_dev_info(struct bnxt *bp,
                               struct hwrm_nvm_get_dev_info_output *nvm_dev_info)
 {
@@ -5711,6 +5745,7 @@ const struct ethtool_ops bnxt_ethtool_ops = {
        .get_eeprom             = bnxt_get_eeprom,
        .set_eeprom             = bnxt_set_eeprom,
        .get_link               = bnxt_get_link,
+       .get_link_ext_state     = bnxt_get_link_ext_state,
        .get_link_ext_stats     = bnxt_get_link_ext_stats,
        .get_eee                = bnxt_get_eee,
        .set_eee                = bnxt_set_eee,
index eb7ff2602fbb0ca700e0738219238440fdb2ebf2..5daa8f225b67d91220343ff3a1871736cdfb08c5 100644 (file)
@@ -603,6 +603,8 @@ enum ethtool_link_ext_state {
        ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED,
        ETHTOOL_LINK_EXT_STATE_OVERHEAT,
        ETHTOOL_LINK_EXT_STATE_MODULE,
+       ETHTOOL_LINK_EXT_STATE_OTP_SPEED_VIOLATION,
+       ETHTOOL_LINK_EXT_STATE_BMC_REQUEST_DOWN,
 };
 
 /* More information in addition to ETHTOOL_LINK_EXT_STATE_AUTONEG. */