u8                      node;
        u8                      tns_mode:1;
        u8                      sqs_mode:1;
+       u8                      loopback_supported:1;
        u16                     mtu;
        struct queue_set        *qs;
 #define        MAX_SQS_PER_VF_SINGLE_NODE              5
 #define        NIC_MBOX_MSG_NICVF_PTR          0x13    /* Send nicvf ptr to PF */
 #define        NIC_MBOX_MSG_PNICVF_PTR         0x14    /* Get primary qset nicvf ptr */
 #define        NIC_MBOX_MSG_SNICVF_PTR         0x15    /* Send sqet nicvf ptr to PVF */
+#define        NIC_MBOX_MSG_LOOPBACK           0x16    /* Set interface in loopback */
 #define        NIC_MBOX_MSG_CFG_DONE           0xF0    /* VF configuration done */
 #define        NIC_MBOX_MSG_SHUTDOWN           0xF1    /* VF is being shutdown */
 
        u8    node_id;
        u8    tns_mode:1;
        u8    sqs_mode:1;
+       u8    loopback_supported:1;
        u8    mac_addr[ETH_ALEN];
 };
 
        u64   nicvf;
 };
 
+/* Set interface in loopback mode */
+struct set_loopback {
+       u8    msg;
+       u8    vf_id;
+       bool  enable;
+};
+
 /* 128 bit shared memory between PF and each VF */
 union nic_mbx {
        struct { u8 msg; }      msg;
        struct bgx_link_status  link_status;
        struct sqs_alloc        sqs_alloc;
        struct nicvf_ptr        nicvf;
+       struct set_loopback     lbk;
 };
 
 #define NIC_NODE_ID_MASK       0x03
 
        }
        mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false;
        mbx.nic_cfg.node_id = nic->node;
+
+       mbx.nic_cfg.loopback_supported = vf < MAX_LMAC;
+
        nic_send_msg_to_vf(nic, vf, &mbx);
 }
 
        nic_send_msg_to_vf(nic, sqs->vf_id, &mbx);
 }
 
+static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
+{
+       int bgx_idx, lmac_idx;
+
+       if (lbk->vf_id > MAX_LMAC)
+               return -1;
+
+       bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
+       lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]);
+
+       bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable);
+
+       return 0;
+}
+
 /* Interrupt handler to handle mailbox messages from VFs */
 static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
 {
        case NIC_MBOX_MSG_BGX_STATS:
                nic_get_bgx_stats(nic, &mbx.bgx_stats);
                goto unlock;
+       case NIC_MBOX_MSG_LOOPBACK:
+               ret = nic_config_loopback(nic, &mbx.lbk);
+               break;
        default:
                dev_err(&nic->pdev->dev,
                        "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
 
                        ether_addr_copy(nic->netdev->dev_addr,
                                        mbx.nic_cfg.mac_addr);
                nic->sqs_mode = mbx.nic_cfg.sqs_mode;
+               nic->loopback_supported = mbx.nic_cfg.loopback_supported;
                nic->link_up = false;
                nic->duplex = 0;
                nic->speed = 0;
        nic->netdev->trans_start = jiffies;
 }
 
+static int nicvf_config_loopback(struct nicvf *nic,
+                                netdev_features_t features)
+{
+       union nic_mbx mbx = {};
+
+       mbx.lbk.msg = NIC_MBOX_MSG_LOOPBACK;
+       mbx.lbk.vf_id = nic->vf_id;
+       mbx.lbk.enable = (features & NETIF_F_LOOPBACK) != 0;
+
+       return nicvf_send_msg_to_pf(nic, &mbx);
+}
+
+static netdev_features_t nicvf_fix_features(struct net_device *netdev,
+                                           netdev_features_t features)
+{
+       struct nicvf *nic = netdev_priv(netdev);
+
+       if ((features & NETIF_F_LOOPBACK) &&
+           netif_running(netdev) && !nic->loopback_supported)
+               features &= ~NETIF_F_LOOPBACK;
+
+       return features;
+}
+
 static int nicvf_set_features(struct net_device *netdev,
                              netdev_features_t features)
 {
        if (changed & NETIF_F_HW_VLAN_CTAG_RX)
                nicvf_config_vlan_stripping(nic, features);
 
+       if ((changed & NETIF_F_LOOPBACK) && netif_running(netdev))
+               return nicvf_config_loopback(nic, features);
+
        return 0;
 }
 
        .ndo_set_mac_address    = nicvf_set_mac_address,
        .ndo_get_stats64        = nicvf_get_stats64,
        .ndo_tx_timeout         = nicvf_tx_timeout,
+       .ndo_fix_features       = nicvf_fix_features,
        .ndo_set_features       = nicvf_set_features,
 };
 
        netdev->hw_features |= NETIF_F_RXHASH;
 
        netdev->features |= netdev->hw_features;
+       netdev->hw_features |= NETIF_F_LOOPBACK;
 
        netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
 
 
        }
 }
 
+/* Configure BGX LMAC in internal loopback mode */
+void bgx_lmac_internal_loopback(int node, int bgx_idx,
+                               int lmac_idx, bool enable)
+{
+       struct bgx *bgx;
+       struct lmac *lmac;
+       u64    cfg;
+
+       bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+       if (!bgx)
+               return;
+
+       lmac = &bgx->lmac[lmac_idx];
+       if (lmac->is_sgmii) {
+               cfg = bgx_reg_read(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL);
+               if (enable)
+                       cfg |= PCS_MRX_CTL_LOOPBACK1;
+               else
+                       cfg &= ~PCS_MRX_CTL_LOOPBACK1;
+               bgx_reg_write(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL, cfg);
+       } else {
+               cfg = bgx_reg_read(bgx, lmac_idx, BGX_SPUX_CONTROL1);
+               if (enable)
+                       cfg |= SPU_CTL_LOOPBACK;
+               else
+                       cfg &= ~SPU_CTL_LOOPBACK;
+               bgx_reg_write(bgx, lmac_idx, BGX_SPUX_CONTROL1, cfg);
+       }
+}
+EXPORT_SYMBOL(bgx_lmac_internal_loopback);
+
 static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid)
 {
        u64 cfg;
 
 
 #define BGX_SPUX_CONTROL1              0x10000
 #define  SPU_CTL_LOW_POWER                     BIT_ULL(11)
+#define  SPU_CTL_LOOPBACK                      BIT_ULL(14)
 #define  SPU_CTL_RESET                         BIT_ULL(15)
 #define BGX_SPUX_STATUS1               0x10008
 #define  SPU_STATUS1_RCV_LNK                   BIT_ULL(2)
 #define         PCS_MRX_CTL_RST_AN                     BIT_ULL(9)
 #define         PCS_MRX_CTL_PWR_DN                     BIT_ULL(11)
 #define         PCS_MRX_CTL_AN_EN                      BIT_ULL(12)
+#define         PCS_MRX_CTL_LOOPBACK1                  BIT_ULL(14)
 #define         PCS_MRX_CTL_RESET                      BIT_ULL(15)
 #define BGX_GMP_PCS_MRX_STATUS         0x30008
 #define         PCS_MRX_STATUS_AN_CPT                  BIT_ULL(5)
 const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid);
 void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac);
 void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status);
+void bgx_lmac_internal_loopback(int node, int bgx_idx,
+                               int lmac_idx, bool enable);
 u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx);
 u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx);
 #define BGX_RX_STATS_COUNT 11