OSDN Git Service

bnxt_en: Implement ethtool set_fec_param() method.
authorMichael Chan <michael.chan@broadcom.com>
Sun, 27 Sep 2020 17:42:19 +0000 (13:42 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sun, 27 Sep 2020 20:35:46 +0000 (13:35 -0700)
This feature allows the user to set the different FEC modes on the NIC
port.  Any new setting will take effect immediately after a link toggle.

Reviewed-by: Vasundhara Volam <vasundhara-v.volam@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c

index 834f64f..38bbd76 100644 (file)
@@ -8890,7 +8890,7 @@ static bool bnxt_support_dropped(u16 advertising, u16 supported)
        return ((supported | diff) != supported);
 }
 
-static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
+int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
 {
        int rc = 0;
        struct bnxt_link_info *link_info = &bp->link_info;
index 8a4c842..7438725 100644 (file)
@@ -1259,6 +1259,49 @@ struct bnxt_link_info {
        struct hwrm_port_phy_qcfg_output phy_qcfg_resp;
 };
 
+#define BNXT_FEC_RS544_ON                                      \
+        (PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_1XN_ENABLE |         \
+         PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_IEEE_ENABLE)
+
+#define BNXT_FEC_RS544_OFF                                     \
+        (PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_1XN_DISABLE |        \
+         PORT_PHY_CFG_REQ_FLAGS_FEC_RS544_IEEE_DISABLE)
+
+#define BNXT_FEC_RS272_ON                                      \
+        (PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_1XN_ENABLE |         \
+         PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_IEEE_ENABLE)
+
+#define BNXT_FEC_RS272_OFF                                     \
+        (PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_1XN_DISABLE |        \
+         PORT_PHY_CFG_REQ_FLAGS_FEC_RS272_IEEE_DISABLE)
+
+#define BNXT_PAM4_SUPPORTED(link_info)                         \
+       ((link_info)->support_pam4_speeds)
+
+#define BNXT_FEC_RS_ON(link_info)                              \
+       (PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE91_ENABLE |           \
+        PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE74_DISABLE |          \
+        (BNXT_PAM4_SUPPORTED(link_info) ?                      \
+         (BNXT_FEC_RS544_ON | BNXT_FEC_RS272_OFF) : 0))
+
+#define BNXT_FEC_LLRS_ON                                       \
+       (PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE91_ENABLE |           \
+        PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE74_DISABLE |          \
+        BNXT_FEC_RS272_ON | BNXT_FEC_RS544_OFF)
+
+#define BNXT_FEC_RS_OFF(link_info)                             \
+       (PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE91_DISABLE |          \
+        (BNXT_PAM4_SUPPORTED(link_info) ?                      \
+         (BNXT_FEC_RS544_OFF | BNXT_FEC_RS272_OFF) : 0))
+
+#define BNXT_FEC_BASE_R_ON(link_info)                          \
+       (PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE74_ENABLE |           \
+        BNXT_FEC_RS_OFF(link_info))
+
+#define BNXT_FEC_ALL_OFF(link_info)                            \
+       (PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE74_DISABLE |          \
+        BNXT_FEC_RS_OFF(link_info))
+
 #define BNXT_MAX_QUEUE 8
 
 struct bnxt_queue_info {
@@ -2125,6 +2168,7 @@ int bnxt_get_avail_msix(struct bnxt *bp, int num);
 int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init);
 void bnxt_tx_disable(struct bnxt *bp);
 void bnxt_tx_enable(struct bnxt *bp);
+int bnxt_update_link(struct bnxt *bp, bool chng_link_state);
 int bnxt_hwrm_set_pause(struct bnxt *);
 int bnxt_hwrm_set_link_setting(struct bnxt *, bool, bool);
 int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp);
index 3dc5d08..0d9fe14 100644 (file)
@@ -1924,6 +1924,67 @@ static int bnxt_get_fecparam(struct net_device *dev,
        return 0;
 }
 
+static u32 bnxt_ethtool_forced_fec_to_fw(struct bnxt_link_info *link_info,
+                                        u32 fec)
+{
+       u32 fw_fec = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE;
+
+       if (fec & ETHTOOL_FEC_BASER)
+               fw_fec |= BNXT_FEC_BASE_R_ON(link_info);
+       else if (fec & ETHTOOL_FEC_RS)
+               fw_fec |= BNXT_FEC_RS_ON(link_info);
+       else if (fec & ETHTOOL_FEC_LLRS)
+               fw_fec |= BNXT_FEC_LLRS_ON;
+       return fw_fec;
+}
+
+static int bnxt_set_fecparam(struct net_device *dev,
+                            struct ethtool_fecparam *fecparam)
+{
+       struct hwrm_port_phy_cfg_input req = {0};
+       struct bnxt *bp = netdev_priv(dev);
+       struct bnxt_link_info *link_info;
+       u32 new_cfg, fec = fecparam->fec;
+       u16 fec_cfg;
+       int rc;
+
+       link_info = &bp->link_info;
+       fec_cfg = link_info->fec_cfg;
+       if (fec_cfg & BNXT_FEC_NONE)
+               return -EOPNOTSUPP;
+
+       if (fec & ETHTOOL_FEC_OFF) {
+               new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_DISABLE |
+                         BNXT_FEC_ALL_OFF(link_info);
+               goto apply_fec;
+       }
+       if (((fec & ETHTOOL_FEC_AUTO) && !(fec_cfg & BNXT_FEC_AUTONEG_CAP)) ||
+           ((fec & ETHTOOL_FEC_RS) && !(fec_cfg & BNXT_FEC_ENC_RS_CAP)) ||
+           ((fec & ETHTOOL_FEC_LLRS) && !(fec_cfg & BNXT_FEC_ENC_LLRS_CAP)) ||
+           ((fec & ETHTOOL_FEC_BASER) && !(fec_cfg & BNXT_FEC_ENC_BASE_R_CAP)))
+               return -EINVAL;
+
+       if (fec & ETHTOOL_FEC_AUTO) {
+               if (!link_info->autoneg)
+                       return -EINVAL;
+               new_cfg = PORT_PHY_CFG_REQ_FLAGS_FEC_AUTONEG_ENABLE;
+       } else {
+               new_cfg = bnxt_ethtool_forced_fec_to_fw(link_info, fec);
+       }
+
+apply_fec:
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1);
+       req.flags = cpu_to_le32(new_cfg | PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
+       rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       /* update current settings */
+       if (!rc) {
+               mutex_lock(&bp->link_lock);
+               bnxt_update_link(bp, false);
+               mutex_unlock(&bp->link_lock);
+       }
+       return rc;
+}
+
 static void bnxt_get_pauseparam(struct net_device *dev,
                                struct ethtool_pauseparam *epause)
 {
@@ -3830,6 +3891,7 @@ const struct ethtool_ops bnxt_ethtool_ops = {
        .get_link_ksettings     = bnxt_get_link_ksettings,
        .set_link_ksettings     = bnxt_set_link_ksettings,
        .get_fecparam           = bnxt_get_fecparam,
+       .set_fecparam           = bnxt_set_fecparam,
        .get_pause_stats        = bnxt_get_pause_stats,
        .get_pauseparam         = bnxt_get_pauseparam,
        .set_pauseparam         = bnxt_set_pauseparam,