diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 06bb5531a47cbf43d04fbaa86f4c7c752ffc9d51..a54f140bb6083f23396994d3744e9b6db41f9770 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -97,7 +97,7 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) break; } - if (ret) + if (ret || h->pdev->revision >= 0x21) return ret; if (en) { @@ -146,6 +146,7 @@ static void hns3_lp_setup_skb(struct sk_buff *skb) { #define HNS3_NIC_LB_DST_MAC_ADDR 0x1f struct net_device *ndev = skb->dev; + struct hnae3_handle *handle; unsigned char *packet; struct ethhdr *ethh; unsigned int i; @@ -166,7 +167,9 @@ static void hns3_lp_setup_skb(struct sk_buff *skb) * before the packet reaches mac or serdes, which will defect * the purpose of mac or serdes selftest. */ - ethh->h_dest[5] += HNS3_NIC_LB_DST_MAC_ADDR; + handle = hns3_get_handle(ndev); + if (handle->pdev->revision == 0x20) + ethh->h_dest[5] += HNS3_NIC_LB_DST_MAC_ADDR; eth_zero_addr(ethh->h_source); ethh->h_proto = htons(ETH_P_ARP); skb_reset_mac_header(skb); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index db5e92151ecd8de65c94c9a27e89c1e35942cb95..4cd3dbd32800604dfff7b6a5c3ca40a9b1c724af 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -228,6 +228,9 @@ enum hclge_opcode_type { HCLGE_OPC_MAC_ETHTYPE_ADD = 0x1010, HCLGE_OPC_MAC_ETHTYPE_REMOVE = 0x1011, + /* MAC VLAN commands */ + HCLGE_OPC_MAC_VLAN_SWITCH_PARAM = 0x1033, + /* VLAN commands */ HCLGE_OPC_VLAN_FILTER_CTRL = 0x1100, HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101, @@ -812,6 +815,19 @@ struct hclge_vlan_filter_vf_cfg_cmd { u8 vf_bitmap[HCLGE_MAX_VF_BYTES]; }; +struct hclge_mac_vlan_switch_cmd { + u8 roce_sel; + u8 rsv1[3]; + __le32 func_id; + u8 swich_param; + u8 rsv2[15]; +}; + +enum hclge_mac_vlan_cfg_sel { + HCLGE_MAC_VLAN_NIC_SEL = 0, + HCLGE_MAC_VLAN_ROCE_SEL, +}; + #define HCLGE_ACCEPT_TAG1_B 0 #define HCLGE_ACCEPT_UNTAG1_B 1 #define HCLGE_PORT_INS_TAG1_EN_B 2 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index e3f76be19f335e144868d7f7287b48f715a067ac..c1c7e7fec6d11e2b3612efa906b28f52579c293e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3712,6 +3712,42 @@ void hclge_handle_imp_error(struct hnae3_handle *handle) } } +static int hclge_config_ssu_loopback(struct hnae3_handle *handle, + bool enable) +{ +#define HCLGE_ALLOW_LOOPBACK_PKTS 0x2 + + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_mac_vlan_switch_cmd *req; + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + int ret; + + req = (struct hclge_mac_vlan_switch_cmd *)desc.data; + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_MAC_VLAN_SWITCH_PARAM, + true); + req->roce_sel = HCLGE_MAC_VLAN_NIC_SEL; + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "query mac vlan switch parameter fail, ret = %d\n", + ret); + return ret; + } + + hclge_cmd_reuse_desc(&desc, false); + if (enable) + req->swich_param |= HCLGE_ALLOW_LOOPBACK_PKTS; + else + req->swich_param &= (~HCLGE_ALLOW_LOOPBACK_PKTS); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) + dev_err(&hdev->pdev->dev, + "set mac vlan switch parameter fail, ret = %d\n", ret); + return ret; +} + static void hclge_reset_subtask(struct hclge_dev *hdev) { struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev); @@ -6495,6 +6531,17 @@ static int hclge_set_loopback(struct hnae3_handle *handle, int ret = 0; int i; + /* Loopback can be enabled in three places: SSU, MAC, and serdes. By + * default, SSU loopback is enabled, so if the SMAC and the DMAC are + * the same, the packets are looped back in the SSU. If SSU loopback + * is disabled, packets can reach MAC even if SMAC is the same as DMAC. + */ + if (hdev->pdev->revision >= 0x21) { + ret = hclge_config_ssu_loopback(handle, !en); + if (ret) + return ret; + } + switch (loop_mode) { case HNAE3_LOOP_APP: ret = hclge_set_app_loopback(hdev, en);