Merge branch 'net-hns3-add-vlan-filter-control-support'
authorJakub Kicinski <kuba@kernel.org>
Tue, 1 Jun 2021 05:53:10 +0000 (22:53 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 1 Jun 2021 05:53:10 +0000 (22:53 -0700)
Huazhong Tan says:

====================
net: hns3: add VLAN filter control support

This patchset add VLAN filter control support for HNS3 driver.
====================

Link: https://lore.kernel.org/r/1622428725-30049-1-git-send-email-tanhuazhong@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
15 files changed:
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h

index a2c17af..0a6cda3 100644 (file)
@@ -20,7 +20,7 @@ enum HCLGE_MBX_OPCODE {
        HCLGE_MBX_API_NEGOTIATE,        /* (VF -> PF) negotiate API version */
        HCLGE_MBX_GET_QINFO,            /* (VF -> PF) get queue config */
        HCLGE_MBX_GET_QDEPTH,           /* (VF -> PF) get queue depth */
-       HCLGE_MBX_GET_TCINFO,           /* (VF -> PF) get TC config */
+       HCLGE_MBX_GET_BASIC_INFO,       /* (VF -> PF) get basic info */
        HCLGE_MBX_GET_RETA,             /* (VF -> PF) get RETA */
        HCLGE_MBX_GET_RSS_KEY,          /* (VF -> PF) get RSS key */
        HCLGE_MBX_GET_MAC_ADDR,         /* (VF -> PF) get MAC addr */
@@ -69,6 +69,7 @@ enum hclge_mbx_vlan_cfg_subcode {
        HCLGE_MBX_VLAN_RX_OFF_CFG,      /* set rx side vlan offload */
        HCLGE_MBX_PORT_BASE_VLAN_CFG,   /* set port based vlan configuration */
        HCLGE_MBX_GET_PORT_BASE_VLAN_STATE,     /* get port based vlan state */
+       HCLGE_MBX_ENABLE_VLAN_FILTER,
 };
 
 enum hclge_mbx_tbl_cfg_subcode {
@@ -85,6 +86,13 @@ struct hclge_ring_chain_param {
        u8 int_gl_index;
 };
 
+struct hclge_basic_info {
+       u8 hw_tc_map;
+       u8 rsv;
+       u16 mbx_api_version;
+       u32 pf_caps;
+};
+
 struct hclgevf_mbx_resp_status {
        struct mutex mbx_mutex; /* protects against contending sync cmd resp */
        u32 origin_mbx_msg;
index 57fa7fc..89b2b7f 100644 (file)
@@ -92,6 +92,8 @@ enum HNAE3_DEV_CAP_BITS {
        HNAE3_DEV_SUPPORT_UDP_TUNNEL_CSUM_B,
        HNAE3_DEV_SUPPORT_PAUSE_B,
        HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
+       HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
+       HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
 };
 
 #define hnae3_dev_fd_supported(hdev) \
@@ -145,6 +147,9 @@ enum HNAE3_DEV_CAP_BITS {
 #define hnae3_ae_dev_rxd_adv_layout_supported(ae_dev) \
        test_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, (ae_dev)->caps)
 
+enum HNAE3_PF_CAP_BITS {
+       HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B = 0,
+};
 #define ring_ptr_move_fw(ring, p) \
        ((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
 #define ring_ptr_move_bw(ring, p) \
@@ -283,6 +288,7 @@ enum hnae3_dbg_cmd {
        HNAE3_DBG_CMD_REG_TQP,
        HNAE3_DBG_CMD_REG_MAC,
        HNAE3_DBG_CMD_REG_DCB,
+       HNAE3_DBG_CMD_VLAN_CONFIG,
        HNAE3_DBG_CMD_QUEUE_MAP,
        HNAE3_DBG_CMD_RX_QUEUE_INFO,
        HNAE3_DBG_CMD_TX_QUEUE_INFO,
@@ -631,7 +637,7 @@ struct hnae3_ae_ops {
        void (*get_mdix_mode)(struct hnae3_handle *handle,
                              u8 *tp_mdix_ctrl, u8 *tp_mdix);
 
-       void (*enable_vlan_filter)(struct hnae3_handle *handle, bool enable);
+       int (*enable_vlan_filter)(struct hnae3_handle *handle, bool enable);
        int (*set_vlan_filter)(struct hnae3_handle *handle, __be16 proto,
                               u16 vlan_id, bool is_kill);
        int (*set_vf_vlan_filter)(struct hnae3_handle *handle, int vfid,
@@ -783,7 +789,6 @@ struct hnae3_roce_private_info {
 #define HNAE3_BPE              BIT(2)  /* broadcast promisc enable */
 #define HNAE3_OVERFLOW_UPE     BIT(3)  /* unicast mac vlan overflow */
 #define HNAE3_OVERFLOW_MPE     BIT(4)  /* multicast mac vlan overflow */
-#define HNAE3_VLAN_FLTR                BIT(5)  /* enable vlan filter */
 #define HNAE3_UPE              (HNAE3_USER_UPE | HNAE3_OVERFLOW_UPE)
 #define HNAE3_MPE              (HNAE3_USER_MPE | HNAE3_OVERFLOW_MPE)
 
index 57ba5a1..cf1efd2 100644 (file)
@@ -309,6 +309,13 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = {
                .buf_len = HNS3_DBG_READ_LEN,
                .init = hns3_dbg_common_file_init,
        },
+       {
+               .name = "vlan_config",
+               .cmd = HNAE3_DBG_CMD_VLAN_CONFIG,
+               .dentry = HNS3_DBG_DENTRY_COMMON,
+               .buf_len = HNS3_DBG_READ_LEN,
+               .init = hns3_dbg_common_file_init,
+       },
 };
 
 static struct hns3_dbg_cap_info hns3_dbg_cap[] = {
@@ -345,7 +352,13 @@ static struct hns3_dbg_cap_info hns3_dbg_cap[] = {
        }, {
                .name = "support rxd advanced layout",
                .cap_bit = HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B,
-       },
+       }, {
+               .name = "support port vlan bypass",
+               .cap_bit = HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
+       }, {
+               .name = "support modify vlan filter state",
+               .cap_bit = HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B,
+       }
 };
 
 static void hns3_dbg_fill_content(char *content, u16 len,
index 43dcf3f..393979b 100644 (file)
@@ -908,13 +908,10 @@ static u8 hns3_get_netdev_flags(struct net_device *netdev)
 {
        u8 flags = 0;
 
-       if (netdev->flags & IFF_PROMISC) {
+       if (netdev->flags & IFF_PROMISC)
                flags = HNAE3_USER_UPE | HNAE3_USER_MPE | HNAE3_BPE;
-       } else {
-               flags |= HNAE3_VLAN_FLTR;
-               if (netdev->flags & IFF_ALLMULTI)
-                       flags |= HNAE3_USER_MPE;
-       }
+       else if (netdev->flags & IFF_ALLMULTI)
+               flags = HNAE3_USER_MPE;
 
        return flags;
 }
@@ -944,25 +941,6 @@ void hns3_request_update_promisc_mode(struct hnae3_handle *handle)
                ops->request_update_promisc_mode(handle);
 }
 
-void hns3_enable_vlan_filter(struct net_device *netdev, bool enable)
-{
-       struct hns3_nic_priv *priv = netdev_priv(netdev);
-       struct hnae3_handle *h = priv->ae_handle;
-       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
-       bool last_state;
-
-       if (ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2 &&
-           h->ae_algo->ops->enable_vlan_filter) {
-               last_state = h->netdev_flags & HNAE3_VLAN_FLTR ? true : false;
-               if (enable != last_state) {
-                       netdev_info(netdev,
-                                   "%s vlan filter\n",
-                                   enable ? "enable" : "disable");
-                       h->ae_algo->ops->enable_vlan_filter(h, enable);
-               }
-       }
-}
-
 static int hns3_set_tso(struct sk_buff *skb, u32 *paylen_fdop_ol4cs,
                        u16 *mss, u32 *type_cs_vlan_tso, u32 *send_bytes)
 {
@@ -1980,6 +1958,14 @@ static int hns3_nic_set_features(struct net_device *netdev,
                return -EINVAL;
        }
 
+       if ((changed & NETIF_F_HW_VLAN_CTAG_FILTER) &&
+           h->ae_algo->ops->enable_vlan_filter) {
+               enable = !!(features & NETIF_F_HW_VLAN_CTAG_FILTER);
+               ret = h->ae_algo->ops->enable_vlan_filter(h, enable);
+               if (ret)
+                       return ret;
+       }
+
        netdev->features = features;
        return 0;
 }
@@ -2825,6 +2811,9 @@ static void hns3_set_default_feature(struct net_device *netdev)
                netdev->hw_features |= NETIF_F_HW_TC;
                netdev->features |= NETIF_F_HW_TC;
        }
+
+       if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps))
+               netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 }
 
 static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
index b038441..5698a14 100644 (file)
@@ -643,7 +643,6 @@ void hns3_set_vector_coalesce_rx_ql(struct hns3_enet_tqp_vector *tqp_vector,
 void hns3_set_vector_coalesce_tx_ql(struct hns3_enet_tqp_vector *tqp_vector,
                                    u32 ql_value);
 
-void hns3_enable_vlan_filter(struct net_device *netdev, bool enable);
 void hns3_request_update_promisc_mode(struct hnae3_handle *handle);
 
 #ifdef CONFIG_HNS3_DCB
index c1ea403..bb7c2ec 100644 (file)
@@ -88,7 +88,6 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
 {
        struct hnae3_handle *h = hns3_get_handle(ndev);
        struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
-       bool vlan_filter_enable;
        int ret;
 
        if (!h->ae_algo->ops->set_loopback ||
@@ -110,14 +109,11 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
        if (ret || ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2)
                return ret;
 
-       if (en) {
+       if (en)
                h->ae_algo->ops->set_promisc_mode(h, true, true);
-       } else {
+       else
                /* recover promisc mode before loopback test */
                hns3_request_update_promisc_mode(h);
-               vlan_filter_enable = ndev->flags & IFF_PROMISC ? false : true;
-               hns3_enable_vlan_filter(ndev, vlan_filter_enable);
-       }
 
        return ret;
 }
index 6aed30c..8f6ed85 100644 (file)
@@ -388,6 +388,10 @@ static void hclge_parse_capability(struct hclge_dev *hdev,
                set_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps);
        if (hnae3_get_bit(caps, HCLGE_CAP_RXD_ADV_LAYOUT_B))
                set_bit(HNAE3_DEV_SUPPORT_RXD_ADV_LAYOUT_B, ae_dev->caps);
+       if (hnae3_get_bit(caps, HCLGE_CAP_PORT_VLAN_BYPASS_B)) {
+               set_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, ae_dev->caps);
+               set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps);
+       }
 }
 
 static __le32 hclge_build_api_caps(void)
index 12558aa..da78a64 100644 (file)
@@ -236,6 +236,7 @@ enum hclge_opcode_type {
        HCLGE_OPC_VLAN_FILTER_CTRL          = 0x1100,
        HCLGE_OPC_VLAN_FILTER_PF_CFG    = 0x1101,
        HCLGE_OPC_VLAN_FILTER_VF_CFG    = 0x1102,
+       HCLGE_OPC_PORT_VLAN_BYPASS      = 0x1103,
 
        /* Flow Director commands */
        HCLGE_OPC_FD_MODE_CTRL          = 0x1200,
@@ -392,6 +393,7 @@ enum HCLGE_CAP_BITS {
        HCLGE_CAP_FEC_B = 13,
        HCLGE_CAP_PAUSE_B = 14,
        HCLGE_CAP_RXD_ADV_LAYOUT_B = 15,
+       HCLGE_CAP_PORT_VLAN_BYPASS_B = 17,
 };
 
 enum HCLGE_API_CAP_BITS {
@@ -527,6 +529,8 @@ struct hclge_pf_res_cmd {
 #define HCLGE_CFG_SPEED_ABILITY_M      GENMASK(7, 0)
 #define HCLGE_CFG_SPEED_ABILITY_EXT_S  10
 #define HCLGE_CFG_SPEED_ABILITY_EXT_M  GENMASK(15, 10)
+#define HCLGE_CFG_VLAN_FLTR_CAP_S      8
+#define HCLGE_CFG_VLAN_FLTR_CAP_M      GENMASK(9, 8)
 #define HCLGE_CFG_UMV_TBL_SPACE_S      16
 #define HCLGE_CFG_UMV_TBL_SPACE_M      GENMASK(31, 16)
 #define HCLGE_CFG_PF_RSS_SIZE_S                0
@@ -811,6 +815,14 @@ struct hclge_vlan_filter_vf_cfg_cmd {
        u8  vf_bitmap[HCLGE_MAX_VF_BYTES];
 };
 
+#define HCLGE_INGRESS_BYPASS_B         0
+struct hclge_port_vlan_filter_bypass_cmd {
+       u8 bypass_state;
+       u8 rsv1[3];
+       u8 vf_id;
+       u8 rsv2[19];
+};
+
 #define HCLGE_SWITCH_ANTI_SPOOF_B      0U
 #define HCLGE_SWITCH_ALW_LPBK_B                1U
 #define HCLGE_SWITCH_ALW_LCL_LPBK_B    2U
index 0b7c683..0d433a5 100644 (file)
@@ -1894,6 +1894,285 @@ static void hclge_dbg_dump_mac_list(struct hclge_dev *hdev, char *buf, int len,
        }
 }
 
+static int hclge_get_vlan_rx_offload_cfg(struct hclge_dev *hdev, u8 vf_id,
+                                        struct hclge_dbg_vlan_cfg *vlan_cfg)
+{
+       struct hclge_vport_vtag_rx_cfg_cmd *req;
+       struct hclge_desc desc;
+       u16 bmap_index;
+       u8 rx_cfg;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_PORT_RX_CFG, true);
+
+       req = (struct hclge_vport_vtag_rx_cfg_cmd *)desc.data;
+       req->vf_offset = vf_id / HCLGE_VF_NUM_PER_CMD;
+       bmap_index = vf_id % HCLGE_VF_NUM_PER_CMD / HCLGE_VF_NUM_PER_BYTE;
+       req->vf_bitmap[bmap_index] = 1U << (vf_id % HCLGE_VF_NUM_PER_BYTE);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "failed to get vport%u rxvlan cfg, ret = %d\n",
+                       vf_id, ret);
+               return ret;
+       }
+
+       rx_cfg = req->vport_vlan_cfg;
+       vlan_cfg->strip_tag1 = hnae3_get_bit(rx_cfg, HCLGE_REM_TAG1_EN_B);
+       vlan_cfg->strip_tag2 = hnae3_get_bit(rx_cfg, HCLGE_REM_TAG2_EN_B);
+       vlan_cfg->drop_tag1 = hnae3_get_bit(rx_cfg, HCLGE_DISCARD_TAG1_EN_B);
+       vlan_cfg->drop_tag2 = hnae3_get_bit(rx_cfg, HCLGE_DISCARD_TAG2_EN_B);
+       vlan_cfg->pri_only1 = hnae3_get_bit(rx_cfg, HCLGE_SHOW_TAG1_EN_B);
+       vlan_cfg->pri_only2 = hnae3_get_bit(rx_cfg, HCLGE_SHOW_TAG2_EN_B);
+
+       return 0;
+}
+
+static int hclge_get_vlan_tx_offload_cfg(struct hclge_dev *hdev, u8 vf_id,
+                                        struct hclge_dbg_vlan_cfg *vlan_cfg)
+{
+       struct hclge_vport_vtag_tx_cfg_cmd *req;
+       struct hclge_desc desc;
+       u16 bmap_index;
+       u8 tx_cfg;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_PORT_TX_CFG, true);
+       req = (struct hclge_vport_vtag_tx_cfg_cmd *)desc.data;
+       req->vf_offset = vf_id / HCLGE_VF_NUM_PER_CMD;
+       bmap_index = vf_id % HCLGE_VF_NUM_PER_CMD / HCLGE_VF_NUM_PER_BYTE;
+       req->vf_bitmap[bmap_index] = 1U << (vf_id % HCLGE_VF_NUM_PER_BYTE);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "failed to get vport%u txvlan cfg, ret = %d\n",
+                       vf_id, ret);
+               return ret;
+       }
+
+       tx_cfg = req->vport_vlan_cfg;
+       vlan_cfg->pvid = le16_to_cpu(req->def_vlan_tag1);
+
+       vlan_cfg->accept_tag1 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_TAG1_B);
+       vlan_cfg->accept_tag2 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_TAG2_B);
+       vlan_cfg->accept_untag1 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_UNTAG1_B);
+       vlan_cfg->accept_untag2 = hnae3_get_bit(tx_cfg, HCLGE_ACCEPT_UNTAG2_B);
+       vlan_cfg->insert_tag1 = hnae3_get_bit(tx_cfg, HCLGE_PORT_INS_TAG1_EN_B);
+       vlan_cfg->insert_tag2 = hnae3_get_bit(tx_cfg, HCLGE_PORT_INS_TAG2_EN_B);
+       vlan_cfg->shift_tag = hnae3_get_bit(tx_cfg, HCLGE_TAG_SHIFT_MODE_EN_B);
+
+       return 0;
+}
+
+static int hclge_get_vlan_filter_config_cmd(struct hclge_dev *hdev,
+                                           u8 vlan_type, u8 vf_id,
+                                           struct hclge_desc *desc)
+{
+       struct hclge_vlan_filter_ctrl_cmd *req;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(desc, HCLGE_OPC_VLAN_FILTER_CTRL, true);
+       req = (struct hclge_vlan_filter_ctrl_cmd *)desc->data;
+       req->vlan_type = vlan_type;
+       req->vf_id = vf_id;
+
+       ret = hclge_cmd_send(&hdev->hw, desc, 1);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "failed to get vport%u vlan filter config, ret = %d.\n",
+                       vf_id, ret);
+
+       return ret;
+}
+
+static int hclge_get_vlan_filter_state(struct hclge_dev *hdev, u8 vlan_type,
+                                      u8 vf_id, u8 *vlan_fe)
+{
+       struct hclge_vlan_filter_ctrl_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       ret = hclge_get_vlan_filter_config_cmd(hdev, vlan_type, vf_id, &desc);
+       if (ret)
+               return ret;
+
+       req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data;
+       *vlan_fe = req->vlan_fe;
+
+       return 0;
+}
+
+static int hclge_get_port_vlan_filter_bypass_state(struct hclge_dev *hdev,
+                                                  u8 vf_id, u8 *bypass_en)
+{
+       struct hclge_port_vlan_filter_bypass_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       if (!test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, hdev->ae_dev->caps))
+               return 0;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PORT_VLAN_BYPASS, true);
+       req = (struct hclge_port_vlan_filter_bypass_cmd *)desc.data;
+       req->vf_id = vf_id;
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "failed to get vport%u port vlan filter bypass state, ret = %d.\n",
+                       vf_id, ret);
+               return ret;
+       }
+
+       *bypass_en = hnae3_get_bit(req->bypass_state, HCLGE_INGRESS_BYPASS_B);
+
+       return 0;
+}
+
+static const struct hclge_dbg_item vlan_filter_items[] = {
+       { "FUNC_ID", 2 },
+       { "I_VF_VLAN_FILTER", 2 },
+       { "E_VF_VLAN_FILTER", 2 },
+       { "PORT_VLAN_FILTER_BYPASS", 0 }
+};
+
+static const struct hclge_dbg_item vlan_offload_items[] = {
+       { "FUNC_ID", 2 },
+       { "PVID", 4 },
+       { "ACCEPT_TAG1", 2 },
+       { "ACCEPT_TAG2", 2 },
+       { "ACCEPT_UNTAG1", 2 },
+       { "ACCEPT_UNTAG2", 2 },
+       { "INSERT_TAG1", 2 },
+       { "INSERT_TAG2", 2 },
+       { "SHIFT_TAG", 2 },
+       { "STRIP_TAG1", 2 },
+       { "STRIP_TAG2", 2 },
+       { "DROP_TAG1", 2 },
+       { "DROP_TAG2", 2 },
+       { "PRI_ONLY_TAG1", 2 },
+       { "PRI_ONLY_TAG2", 0 }
+};
+
+static int hclge_dbg_dump_vlan_filter_config(struct hclge_dev *hdev, char *buf,
+                                            int len, int *pos)
+{
+       char content[HCLGE_DBG_VLAN_FLTR_INFO_LEN], str_id[HCLGE_DBG_ID_LEN];
+       const char *result[ARRAY_SIZE(vlan_filter_items)];
+       u8 i, j, vlan_fe, bypass, ingress, egress;
+       u8 func_num = pci_num_vf(hdev->pdev) + 1; /* pf and enabled vf num */
+       int ret;
+
+       ret = hclge_get_vlan_filter_state(hdev, HCLGE_FILTER_TYPE_PORT, 0,
+                                         &vlan_fe);
+       if (ret)
+               return ret;
+       ingress = vlan_fe & HCLGE_FILTER_FE_NIC_INGRESS_B;
+       egress = vlan_fe & HCLGE_FILTER_FE_NIC_EGRESS_B ? 1 : 0;
+
+       *pos += scnprintf(buf, len, "I_PORT_VLAN_FILTER: %s\n",
+                         state_str[ingress]);
+       *pos += scnprintf(buf + *pos, len - *pos, "E_PORT_VLAN_FILTER: %s\n",
+                         state_str[egress]);
+
+       hclge_dbg_fill_content(content, sizeof(content), vlan_filter_items,
+                              NULL, ARRAY_SIZE(vlan_filter_items));
+       *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+
+       for (i = 0; i < func_num; i++) {
+               ret = hclge_get_vlan_filter_state(hdev, HCLGE_FILTER_TYPE_VF, i,
+                                                 &vlan_fe);
+               if (ret)
+                       return ret;
+
+               ingress = vlan_fe & HCLGE_FILTER_FE_NIC_INGRESS_B;
+               egress = vlan_fe & HCLGE_FILTER_FE_NIC_EGRESS_B ? 1 : 0;
+               ret = hclge_get_port_vlan_filter_bypass_state(hdev, i, &bypass);
+               if (ret)
+                       return ret;
+               j = 0;
+               result[j++] = hclge_dbg_get_func_id_str(str_id, i);
+               result[j++] = state_str[ingress];
+               result[j++] = state_str[egress];
+               result[j++] =
+                       test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B,
+                                hdev->ae_dev->caps) ? state_str[bypass] : "NA";
+               hclge_dbg_fill_content(content, sizeof(content),
+                                      vlan_filter_items, result,
+                                      ARRAY_SIZE(vlan_filter_items));
+               *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+       }
+       *pos += scnprintf(buf + *pos, len - *pos, "\n");
+
+       return 0;
+}
+
+static int hclge_dbg_dump_vlan_offload_config(struct hclge_dev *hdev, char *buf,
+                                             int len, int *pos)
+{
+       char str_id[HCLGE_DBG_ID_LEN], str_pvid[HCLGE_DBG_ID_LEN];
+       const char *result[ARRAY_SIZE(vlan_offload_items)];
+       char content[HCLGE_DBG_VLAN_OFFLOAD_INFO_LEN];
+       u8 func_num = pci_num_vf(hdev->pdev) + 1; /* pf and enabled vf num */
+       struct hclge_dbg_vlan_cfg vlan_cfg;
+       int ret;
+       u8 i, j;
+
+       hclge_dbg_fill_content(content, sizeof(content), vlan_offload_items,
+                              NULL, ARRAY_SIZE(vlan_offload_items));
+       *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+
+       for (i = 0; i < func_num; i++) {
+               ret = hclge_get_vlan_tx_offload_cfg(hdev, i, &vlan_cfg);
+               if (ret)
+                       return ret;
+
+               ret = hclge_get_vlan_rx_offload_cfg(hdev, i, &vlan_cfg);
+               if (ret)
+                       return ret;
+
+               sprintf(str_pvid, "%u", vlan_cfg.pvid);
+               j = 0;
+               result[j++] = hclge_dbg_get_func_id_str(str_id, i);
+               result[j++] = str_pvid;
+               result[j++] = state_str[vlan_cfg.accept_tag1];
+               result[j++] = state_str[vlan_cfg.accept_tag2];
+               result[j++] = state_str[vlan_cfg.accept_untag1];
+               result[j++] = state_str[vlan_cfg.accept_untag2];
+               result[j++] = state_str[vlan_cfg.insert_tag1];
+               result[j++] = state_str[vlan_cfg.insert_tag2];
+               result[j++] = state_str[vlan_cfg.shift_tag];
+               result[j++] = state_str[vlan_cfg.strip_tag1];
+               result[j++] = state_str[vlan_cfg.strip_tag2];
+               result[j++] = state_str[vlan_cfg.drop_tag1];
+               result[j++] = state_str[vlan_cfg.drop_tag2];
+               result[j++] = state_str[vlan_cfg.pri_only1];
+               result[j++] = state_str[vlan_cfg.pri_only2];
+
+               hclge_dbg_fill_content(content, sizeof(content),
+                                      vlan_offload_items, result,
+                                      ARRAY_SIZE(vlan_offload_items));
+               *pos += scnprintf(buf + *pos, len - *pos, "%s", content);
+       }
+
+       return 0;
+}
+
+static int hclge_dbg_dump_vlan_config(struct hclge_dev *hdev, char *buf,
+                                     int len)
+{
+       int pos = 0;
+       int ret;
+
+       ret = hclge_dbg_dump_vlan_filter_config(hdev, buf, len, &pos);
+       if (ret)
+               return ret;
+
+       return hclge_dbg_dump_vlan_offload_config(hdev, buf, len, &pos);
+}
+
 static int hclge_dbg_dump_mac_uc(struct hclge_dev *hdev, char *buf, int len)
 {
        hclge_dbg_dump_mac_list(hdev, buf, len, true);
@@ -2037,6 +2316,10 @@ static const struct hclge_dbg_func hclge_dbg_cmd_func[] = {
                .cmd = HNAE3_DBG_CMD_SERV_INFO,
                .dbg_dump = hclge_dbg_dump_serv_info,
        },
+       {
+               .cmd = HNAE3_DBG_CMD_VLAN_CONFIG,
+               .dbg_dump = hclge_dbg_dump_vlan_config,
+       },
 };
 
 int hclge_dbg_read_cmd(struct hnae3_handle *handle, enum hnae3_dbg_cmd cmd,
index 642752e..c526591 100644 (file)
@@ -735,6 +735,8 @@ static const struct hclge_dbg_dfx_message hclge_dbg_tqp_reg[] = {
 };
 
 #define HCLGE_DBG_INFO_LEN                     256
+#define HCLGE_DBG_VLAN_FLTR_INFO_LEN           256
+#define HCLGE_DBG_VLAN_OFFLOAD_INFO_LEN                512
 #define HCLGE_DBG_ID_LEN                       16
 #define HCLGE_DBG_ITEM_NAME_LEN                        32
 #define HCLGE_DBG_DATA_STR_LEN                 32
@@ -747,4 +749,21 @@ struct hclge_dbg_item {
        u16 interval; /* blank numbers after the item */
 };
 
+struct hclge_dbg_vlan_cfg {
+       u16 pvid;
+       u8 accept_tag1;
+       u8 accept_tag2;
+       u8 accept_untag1;
+       u8 accept_untag2;
+       u8 insert_tag1;
+       u8 insert_tag2;
+       u8 shift_tag;
+       u8 strip_tag1;
+       u8 strip_tag2;
+       u8 drop_tag1;
+       u8 drop_tag2;
+       u8 pri_only1;
+       u8 pri_only2;
+};
+
 #endif
index 6addeb2..6ecc106 100644 (file)
@@ -1334,6 +1334,10 @@ static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc)
                                            HCLGE_CFG_SPEED_ABILITY_EXT_S);
        cfg->speed_ability |= speed_ability_ext << SPEED_ABILITY_EXT_SHIFT;
 
+       cfg->vlan_fliter_cap = hnae3_get_field(__le32_to_cpu(req->param[1]),
+                                              HCLGE_CFG_VLAN_FLTR_CAP_M,
+                                              HCLGE_CFG_VLAN_FLTR_CAP_S);
+
        cfg->umv_space = hnae3_get_field(__le32_to_cpu(req->param[1]),
                                         HCLGE_CFG_UMV_TBL_SPACE_M,
                                         HCLGE_CFG_UMV_TBL_SPACE_S);
@@ -1513,6 +1517,7 @@ static void hclge_init_kdump_kernel_config(struct hclge_dev *hdev)
 
 static int hclge_configure(struct hclge_dev *hdev)
 {
+       struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
        struct hclge_cfg cfg;
        unsigned int i;
        int ret;
@@ -1534,6 +1539,8 @@ static int hclge_configure(struct hclge_dev *hdev)
        hdev->tc_max = cfg.tc_num;
        hdev->tm_info.hw_pfc_map = 0;
        hdev->wanted_umv_size = cfg.umv_space;
+       if (cfg.vlan_fliter_cap == HCLGE_VLAN_FLTR_CAN_MDF)
+               set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps);
 
        if (hnae3_dev_fd_supported(hdev)) {
                hdev->fd_en = true;
@@ -1843,6 +1850,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev)
                vport->mps = HCLGE_MAC_DEFAULT_FRAME;
                vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE;
                vport->rxvlan_cfg.rx_vlan_offload_en = true;
+               vport->req_vlan_fltr_en = true;
                INIT_LIST_HEAD(&vport->vlan_list);
                INIT_LIST_HEAD(&vport->uc_mac_list);
                INIT_LIST_HEAD(&vport->mc_mac_list);
@@ -9381,6 +9389,28 @@ static int hclge_do_ioctl(struct hnae3_handle *handle, struct ifreq *ifr,
        return phy_mii_ioctl(hdev->hw.mac.phydev, ifr, cmd);
 }
 
+static int hclge_set_port_vlan_filter_bypass(struct hclge_dev *hdev, u8 vf_id,
+                                            bool bypass_en)
+{
+       struct hclge_port_vlan_filter_bypass_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_PORT_VLAN_BYPASS, false);
+       req = (struct hclge_port_vlan_filter_bypass_cmd *)desc.data;
+       req->vf_id = vf_id;
+       hnae3_set_bit(req->bypass_state, HCLGE_INGRESS_BYPASS_B,
+                     bypass_en ? 1 : 0);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "failed to set vport%u port vlan filter bypass state, ret = %d.\n",
+                       vf_id, ret);
+
+       return ret;
+}
+
 static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
                                      u8 fe_type, bool filter_en, u8 vf_id)
 {
@@ -9414,37 +9444,99 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
        return ret;
 }
 
-#define HCLGE_FILTER_TYPE_VF           0
-#define HCLGE_FILTER_TYPE_PORT         1
-#define HCLGE_FILTER_FE_EGRESS_V1_B    BIT(0)
-#define HCLGE_FILTER_FE_NIC_INGRESS_B  BIT(0)
-#define HCLGE_FILTER_FE_NIC_EGRESS_B   BIT(1)
-#define HCLGE_FILTER_FE_ROCE_INGRESS_B BIT(2)
-#define HCLGE_FILTER_FE_ROCE_EGRESS_B  BIT(3)
-#define HCLGE_FILTER_FE_EGRESS         (HCLGE_FILTER_FE_NIC_EGRESS_B \
-                                       | HCLGE_FILTER_FE_ROCE_EGRESS_B)
-#define HCLGE_FILTER_FE_INGRESS                (HCLGE_FILTER_FE_NIC_INGRESS_B \
-                                       | HCLGE_FILTER_FE_ROCE_INGRESS_B)
+static int hclge_set_vport_vlan_filter(struct hclge_vport *vport, bool enable)
+{
+       struct hclge_dev *hdev = vport->back;
+       struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
+       int ret;
+
+       if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2)
+               return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+                                                 HCLGE_FILTER_FE_EGRESS_V1_B,
+                                                 enable, vport->vport_id);
+
+       ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
+                                        HCLGE_FILTER_FE_EGRESS, enable,
+                                        vport->vport_id);
+       if (ret)
+               return ret;
+
+       if (test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, ae_dev->caps))
+               ret = hclge_set_port_vlan_filter_bypass(hdev, vport->vport_id,
+                                                       !enable);
+       else if (!vport->vport_id)
+               ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
+                                                HCLGE_FILTER_FE_INGRESS,
+                                                enable, 0);
 
-static void hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
+       return ret;
+}
+
+static bool hclge_need_enable_vport_vlan_filter(struct hclge_vport *vport)
 {
-       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hnae3_handle *handle = &vport->nic;
+       struct hclge_vport_vlan_cfg *vlan, *tmp;
        struct hclge_dev *hdev = vport->back;
 
-       if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V2) {
-               hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
-                                          HCLGE_FILTER_FE_EGRESS, enable, 0);
-               hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
-                                          HCLGE_FILTER_FE_INGRESS, enable, 0);
-       } else {
-               hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
-                                          HCLGE_FILTER_FE_EGRESS_V1_B, enable,
-                                          0);
+       if (vport->vport_id) {
+               if (vport->port_base_vlan_cfg.state !=
+                       HNAE3_PORT_BASE_VLAN_DISABLE)
+                       return true;
+
+               if (vport->vf_info.trusted && vport->vf_info.request_uc_en)
+                       return false;
+       } else if (handle->netdev_flags & HNAE3_USER_UPE) {
+               return false;
        }
-       if (enable)
-               handle->netdev_flags |= HNAE3_VLAN_FLTR;
-       else
-               handle->netdev_flags &= ~HNAE3_VLAN_FLTR;
+
+       if (!vport->req_vlan_fltr_en)
+               return false;
+
+       /* compatible with former device, always enable vlan filter */
+       if (!test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps))
+               return true;
+
+       list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node)
+               if (vlan->vlan_id != 0)
+                       return true;
+
+       return false;
+}
+
+int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en)
+{
+       struct hclge_dev *hdev = vport->back;
+       bool need_en;
+       int ret;
+
+       mutex_lock(&hdev->vport_lock);
+
+       vport->req_vlan_fltr_en = request_en;
+
+       need_en = hclge_need_enable_vport_vlan_filter(vport);
+       if (need_en == vport->cur_vlan_fltr_en) {
+               mutex_unlock(&hdev->vport_lock);
+               return 0;
+       }
+
+       ret = hclge_set_vport_vlan_filter(vport, need_en);
+       if (ret) {
+               mutex_unlock(&hdev->vport_lock);
+               return ret;
+       }
+
+       vport->cur_vlan_fltr_en = need_en;
+
+       mutex_unlock(&hdev->vport_lock);
+
+       return 0;
+}
+
+static int hclge_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+
+       return hclge_enable_vport_vlan_filter(vport, enable);
 }
 
 static int hclge_set_vf_vlan_filter_cmd(struct hclge_dev *hdev, u16 vfid,
@@ -9724,7 +9816,7 @@ static int hclge_set_vlan_rx_offload_cfg(struct hclge_vport *vport)
 
 static int hclge_vlan_offload_cfg(struct hclge_vport *vport,
                                  u16 port_base_vlan_state,
-                                 u16 vlan_tag)
+                                 u16 vlan_tag, u8 qos)
 {
        int ret;
 
@@ -9738,7 +9830,8 @@ static int hclge_vlan_offload_cfg(struct hclge_vport *vport,
                vport->txvlan_cfg.accept_tag1 =
                        ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3;
                vport->txvlan_cfg.insert_tag1_en = true;
-               vport->txvlan_cfg.default_tag1 = vlan_tag;
+               vport->txvlan_cfg.default_tag1 = (qos << VLAN_PRIO_SHIFT) |
+                                                vlan_tag;
        }
 
        vport->txvlan_cfg.accept_untag1 = true;
@@ -9837,6 +9930,7 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
                                                         vport->vport_id);
                        if (ret)
                                return ret;
+                       vport->cur_vlan_fltr_en = true;
                }
 
                ret = hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT,
@@ -9852,8 +9946,6 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
                        return ret;
        }
 
-       handle->netdev_flags |= HNAE3_VLAN_FLTR;
-
        hdev->vlan_type_cfg.rx_in_fst_vlan_type = HCLGE_DEF_VLAN_TYPE;
        hdev->vlan_type_cfg.rx_in_sec_vlan_type = HCLGE_DEF_VLAN_TYPE;
        hdev->vlan_type_cfg.rx_ot_fst_vlan_type = HCLGE_DEF_VLAN_TYPE;
@@ -9867,13 +9959,15 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev)
 
        for (i = 0; i < hdev->num_alloc_vport; i++) {
                u16 vlan_tag;
+               u8 qos;
 
                vport = &hdev->vport[i];
                vlan_tag = vport->port_base_vlan_cfg.vlan_info.vlan_tag;
+               qos = vport->port_base_vlan_cfg.vlan_info.qos;
 
                ret = hclge_vlan_offload_cfg(vport,
                                             vport->port_base_vlan_cfg.state,
-                                            vlan_tag);
+                                            vlan_tag, qos);
                if (ret)
                        return ret;
        }
@@ -10074,6 +10168,14 @@ int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
        return hclge_set_vlan_rx_offload_cfg(vport);
 }
 
+static void hclge_set_vport_vlan_fltr_change(struct hclge_vport *vport)
+{
+       struct hclge_dev *hdev = vport->back;
+
+       if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps))
+               set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE, &vport->state);
+}
+
 static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
                                            u16 port_base_vlan_state,
                                            struct hclge_vlan_info *new_info,
@@ -10084,6 +10186,10 @@ static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
 
        if (port_base_vlan_state == HNAE3_PORT_BASE_VLAN_ENABLE) {
                hclge_rm_vport_all_vlan_table(vport, false);
+               /* force clear VLAN 0 */
+               ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, true, 0);
+               if (ret)
+                       return ret;
                return hclge_set_vlan_filter_hw(hdev,
                                                 htons(new_info->vlan_proto),
                                                 vport->vport_id,
@@ -10091,6 +10197,11 @@ static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
                                                 false);
        }
 
+       /* force add VLAN 0 */
+       ret = hclge_set_vf_vlan_common(hdev, vport->vport_id, false, 0);
+       if (ret)
+               return ret;
+
        ret = hclge_set_vlan_filter_hw(hdev, htons(old_info->vlan_proto),
                                       vport->vport_id, old_info->vlan_tag,
                                       true);
@@ -10100,6 +10211,18 @@ static int hclge_update_vlan_filter_entries(struct hclge_vport *vport,
        return hclge_add_vport_all_vlan_table(vport);
 }
 
+static bool hclge_need_update_vlan_filter(const struct hclge_vlan_info *new_cfg,
+                                         const struct hclge_vlan_info *old_cfg)
+{
+       if (new_cfg->vlan_tag != old_cfg->vlan_tag)
+               return true;
+
+       if (new_cfg->vlan_tag == 0 && (new_cfg->qos == 0 || old_cfg->qos == 0))
+               return true;
+
+       return false;
+}
+
 int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
                                    struct hclge_vlan_info *vlan_info)
 {
@@ -10110,10 +10233,14 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
 
        old_vlan_info = &vport->port_base_vlan_cfg.vlan_info;
 
-       ret = hclge_vlan_offload_cfg(vport, state, vlan_info->vlan_tag);
+       ret = hclge_vlan_offload_cfg(vport, state, vlan_info->vlan_tag,
+                                    vlan_info->qos);
        if (ret)
                return ret;
 
+       if (!hclge_need_update_vlan_filter(vlan_info, old_vlan_info))
+               goto out;
+
        if (state == HNAE3_PORT_BASE_VLAN_MODIFY) {
                /* add new VLAN tag */
                ret = hclge_set_vlan_filter_hw(hdev,
@@ -10125,15 +10252,23 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
                        return ret;
 
                /* remove old VLAN tag */
-               ret = hclge_set_vlan_filter_hw(hdev,
-                                              htons(old_vlan_info->vlan_proto),
-                                              vport->vport_id,
-                                              old_vlan_info->vlan_tag,
-                                              true);
-               if (ret)
+               if (old_vlan_info->vlan_tag == 0)
+                       ret = hclge_set_vf_vlan_common(hdev, vport->vport_id,
+                                                      true, 0);
+               else
+                       ret = hclge_set_vlan_filter_hw(hdev,
+                                                      htons(ETH_P_8021Q),
+                                                      vport->vport_id,
+                                                      old_vlan_info->vlan_tag,
+                                                      true);
+               if (ret) {
+                       dev_err(&hdev->pdev->dev,
+                               "failed to clear vport%u port base vlan %u, ret = %d.\n",
+                               vport->vport_id, old_vlan_info->vlan_tag, ret);
                        return ret;
+               }
 
-               goto update;
+               goto out;
        }
 
        ret = hclge_update_vlan_filter_entries(vport, state, vlan_info,
@@ -10141,38 +10276,38 @@ int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
        if (ret)
                return ret;
 
-       /* update state only when disable/enable port based VLAN */
+out:
        vport->port_base_vlan_cfg.state = state;
        if (state == HNAE3_PORT_BASE_VLAN_DISABLE)
                nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_DISABLE;
        else
                nic->port_base_vlan_state = HNAE3_PORT_BASE_VLAN_ENABLE;
 
-update:
-       vport->port_base_vlan_cfg.vlan_info.vlan_tag = vlan_info->vlan_tag;
-       vport->port_base_vlan_cfg.vlan_info.qos = vlan_info->qos;
-       vport->port_base_vlan_cfg.vlan_info.vlan_proto = vlan_info->vlan_proto;
+       vport->port_base_vlan_cfg.vlan_info = *vlan_info;
+       hclge_set_vport_vlan_fltr_change(vport);
 
        return 0;
 }
 
 static u16 hclge_get_port_base_vlan_state(struct hclge_vport *vport,
                                          enum hnae3_port_base_vlan_state state,
-                                         u16 vlan)
+                                         u16 vlan, u8 qos)
 {
        if (state == HNAE3_PORT_BASE_VLAN_DISABLE) {
-               if (!vlan)
+               if (!vlan && !qos)
                        return HNAE3_PORT_BASE_VLAN_NOCHANGE;
-               else
-                       return HNAE3_PORT_BASE_VLAN_ENABLE;
-       } else {
-               if (!vlan)
-                       return HNAE3_PORT_BASE_VLAN_DISABLE;
-               else if (vport->port_base_vlan_cfg.vlan_info.vlan_tag == vlan)
-                       return HNAE3_PORT_BASE_VLAN_NOCHANGE;
-               else
-                       return HNAE3_PORT_BASE_VLAN_MODIFY;
+
+               return HNAE3_PORT_BASE_VLAN_ENABLE;
        }
+
+       if (!vlan && !qos)
+               return HNAE3_PORT_BASE_VLAN_DISABLE;
+
+       if (vport->port_base_vlan_cfg.vlan_info.vlan_tag == vlan &&
+           vport->port_base_vlan_cfg.vlan_info.qos == qos)
+               return HNAE3_PORT_BASE_VLAN_NOCHANGE;
+
+       return HNAE3_PORT_BASE_VLAN_MODIFY;
 }
 
 static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
@@ -10200,7 +10335,7 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
 
        state = hclge_get_port_base_vlan_state(vport,
                                               vport->port_base_vlan_cfg.state,
-                                              vlan);
+                                              vlan, qos);
        if (state == HNAE3_PORT_BASE_VLAN_NOCHANGE)
                return 0;
 
@@ -10223,8 +10358,7 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
            test_bit(HCLGE_VPORT_STATE_ALIVE, &vport->state))
                hclge_push_vf_port_base_vlan_info(&hdev->vport[0],
                                                  vport->vport_id, state,
-                                                 vlan, qos,
-                                                 ntohs(proto));
+                                                 &vlan_info);
 
        return 0;
 }
@@ -10294,9 +10428,37 @@ int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
                 */
                set_bit(vlan_id, vport->vlan_del_fail_bmap);
        }
+
+       hclge_set_vport_vlan_fltr_change(vport);
+
        return ret;
 }
 
+static void hclge_sync_vlan_fltr_state(struct hclge_dev *hdev)
+{
+       struct hclge_vport *vport;
+       int ret;
+       u16 i;
+
+       for (i = 0; i < hdev->num_alloc_vport; i++) {
+               vport = &hdev->vport[i];
+               if (!test_and_clear_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
+                                       &vport->state))
+                       continue;
+
+               ret = hclge_enable_vport_vlan_filter(vport,
+                                                    vport->req_vlan_fltr_en);
+               if (ret) {
+                       dev_err(&hdev->pdev->dev,
+                               "failed to sync vlan filter state for vport%u, ret = %d\n",
+                               vport->vport_id, ret);
+                       set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
+                               &vport->state);
+                       return;
+               }
+       }
+}
+
 static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
 {
 #define HCLGE_MAX_SYNC_COUNT   60
@@ -10319,6 +10481,7 @@ static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
 
                        clear_bit(vlan_id, vport->vlan_del_fail_bmap);
                        hclge_rm_vport_vlan_table(vport, vlan_id, false);
+                       hclge_set_vport_vlan_fltr_change(vport);
 
                        sync_cnt++;
                        if (sync_cnt >= HCLGE_MAX_SYNC_COUNT)
@@ -10328,6 +10491,8 @@ static void hclge_sync_vlan_filter(struct hclge_dev *hdev)
                                                 VLAN_N_VID);
                }
        }
+
+       hclge_sync_vlan_fltr_state(hdev);
 }
 
 static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps)
@@ -12418,8 +12583,8 @@ static void hclge_sync_promisc_mode(struct hclge_dev *hdev)
                if (!ret) {
                        clear_bit(HCLGE_VPORT_STATE_PROMISC_CHANGE,
                                  &vport->state);
-                       hclge_enable_vlan_filter(handle,
-                                                tmp_flags & HNAE3_VLAN_FLTR);
+                       set_bit(HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
+                               &vport->state);
                }
        }
 
@@ -12447,6 +12612,7 @@ static void hclge_sync_promisc_mode(struct hclge_dev *hdev)
                                &vport->state);
                        return;
                }
+               hclge_set_vport_vlan_fltr_change(vport);
        }
 }
 
index 9e4d02d..7595f84 100644 (file)
@@ -321,6 +321,22 @@ enum hclge_fc_mode {
        HCLGE_FC_DEFAULT
 };
 
+#define HCLGE_FILTER_TYPE_VF           0
+#define HCLGE_FILTER_TYPE_PORT         1
+#define HCLGE_FILTER_FE_EGRESS_V1_B    BIT(0)
+#define HCLGE_FILTER_FE_NIC_INGRESS_B  BIT(0)
+#define HCLGE_FILTER_FE_NIC_EGRESS_B   BIT(1)
+#define HCLGE_FILTER_FE_ROCE_INGRESS_B BIT(2)
+#define HCLGE_FILTER_FE_ROCE_EGRESS_B  BIT(3)
+#define HCLGE_FILTER_FE_EGRESS         (HCLGE_FILTER_FE_NIC_EGRESS_B \
+                                       | HCLGE_FILTER_FE_ROCE_EGRESS_B)
+#define HCLGE_FILTER_FE_INGRESS                (HCLGE_FILTER_FE_NIC_INGRESS_B \
+                                       | HCLGE_FILTER_FE_ROCE_INGRESS_B)
+
+enum hclge_vlan_fltr_cap {
+       HCLGE_VLAN_FLTR_DEF,
+       HCLGE_VLAN_FLTR_CAN_MDF,
+};
 enum hclge_link_fail_code {
        HCLGE_LF_NORMAL,
        HCLGE_LF_REF_CLOCK_LOST,
@@ -351,6 +367,7 @@ struct hclge_tc_info {
 
 struct hclge_cfg {
        u8 tc_num;
+       u8 vlan_fliter_cap;
        u16 tqp_desc_num;
        u16 rx_buf_len;
        u16 vf_rss_size_max;
@@ -759,9 +776,14 @@ struct hclge_mac_tnl_stats {
 struct hclge_vf_vlan_cfg {
        u8 mbx_cmd;
        u8 subcode;
-       u8 is_kill;
-       u16 vlan;
-       u16 proto;
+       union {
+               struct {
+                       u8 is_kill;
+                       u16 vlan;
+                       u16 proto;
+               };
+               u8 enable;
+       };
 };
 
 #pragma pack()
@@ -952,6 +974,7 @@ enum HCLGE_VPORT_STATE {
        HCLGE_VPORT_STATE_ALIVE,
        HCLGE_VPORT_STATE_MAC_TBL_CHANGE,
        HCLGE_VPORT_STATE_PROMISC_CHANGE,
+       HCLGE_VPORT_STATE_VLAN_FLTR_CHANGE,
        HCLGE_VPORT_STATE_MAX
 };
 
@@ -993,6 +1016,8 @@ struct hclge_vport {
        u32 bw_limit;           /* VSI BW Limit (0 = disabled) */
        u8  dwrr;
 
+       bool req_vlan_fltr_en;
+       bool cur_vlan_fltr_en;
        unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)];
        struct hclge_port_base_vlan_config port_base_vlan_cfg;
        struct hclge_tx_vtag_cfg  txvlan_cfg;
@@ -1084,8 +1109,8 @@ void hclge_restore_vport_vlan_table(struct hclge_vport *vport);
 int hclge_update_port_base_vlan_cfg(struct hclge_vport *vport, u16 state,
                                    struct hclge_vlan_info *vlan_info);
 int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
-                                     u16 state, u16 vlan_tag, u16 qos,
-                                     u16 vlan_proto);
+                                     u16 state,
+                                     struct hclge_vlan_info *vlan_info);
 void hclge_task_schedule(struct hclge_dev *hdev, unsigned long delay_time);
 int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev,
                                struct hclge_desc *desc);
@@ -1094,4 +1119,5 @@ void hclge_report_hw_error(struct hclge_dev *hdev,
 void hclge_inform_vf_promisc_info(struct hclge_vport *vport);
 int hclge_dbg_dump_rst_info(struct hclge_dev *hdev, char *buf, int len);
 int hclge_push_vf_link_status(struct hclge_vport *vport);
+int hclge_enable_vport_vlan_filter(struct hclge_vport *vport, bool request_en);
 #endif
index 851408b..e10a2c3 100644 (file)
@@ -318,17 +318,17 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport,
 }
 
 int hclge_push_vf_port_base_vlan_info(struct hclge_vport *vport, u8 vfid,
-                                     u16 state, u16 vlan_tag, u16 qos,
-                                     u16 vlan_proto)
+                                     u16 state,
+                                     struct hclge_vlan_info *vlan_info)
 {
 #define MSG_DATA_SIZE  8
 
        u8 msg_data[MSG_DATA_SIZE];
 
        memcpy(&msg_data[0], &state, sizeof(u16));
-       memcpy(&msg_data[2], &vlan_proto, sizeof(u16));
-       memcpy(&msg_data[4], &qos, sizeof(u16));
-       memcpy(&msg_data[6], &vlan_tag, sizeof(u16));
+       memcpy(&msg_data[2], &vlan_info->vlan_proto, sizeof(u16));
+       memcpy(&msg_data[4], &vlan_info->qos, sizeof(u16));
+       memcpy(&msg_data[6], &vlan_info->vlan_tag, sizeof(u16));
 
        return hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data),
                                  HCLGE_MBX_PUSH_VLAN_INFO, vfid);
@@ -341,49 +341,35 @@ static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
 #define HCLGE_MBX_VLAN_STATE_OFFSET    0
 #define HCLGE_MBX_VLAN_INFO_OFFSET     2
 
+       struct hnae3_handle *handle = &vport->nic;
+       struct hclge_dev *hdev = vport->back;
        struct hclge_vf_vlan_cfg *msg_cmd;
-       int status = 0;
 
        msg_cmd = (struct hclge_vf_vlan_cfg *)&mbx_req->msg;
-       if (msg_cmd->subcode == HCLGE_MBX_VLAN_FILTER) {
-               struct hnae3_handle *handle = &vport->nic;
-               u16 vlan, proto;
-               bool is_kill;
-
-               is_kill = !!msg_cmd->is_kill;
-               vlan =  msg_cmd->vlan;
-               proto =  msg_cmd->proto;
-               status = hclge_set_vlan_filter(handle, cpu_to_be16(proto),
-                                              vlan, is_kill);
-       } else if (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) {
-               struct hnae3_handle *handle = &vport->nic;
-               bool en = msg_cmd->is_kill ? true : false;
-
-               status = hclge_en_hw_strip_rxvtag(handle, en);
-       } else if (msg_cmd->subcode == HCLGE_MBX_PORT_BASE_VLAN_CFG) {
-               struct hclge_vlan_info *vlan_info;
-               u16 *state;
-
-               state = (u16 *)&mbx_req->msg.data[HCLGE_MBX_VLAN_STATE_OFFSET];
-               vlan_info = (struct hclge_vlan_info *)
-                       &mbx_req->msg.data[HCLGE_MBX_VLAN_INFO_OFFSET];
-               status = hclge_update_port_base_vlan_cfg(vport, *state,
-                                                        vlan_info);
-       } else if (msg_cmd->subcode == HCLGE_MBX_GET_PORT_BASE_VLAN_STATE) {
-               struct hnae3_ae_dev *ae_dev = pci_get_drvdata(vport->nic.pdev);
+       switch (msg_cmd->subcode) {
+       case HCLGE_MBX_VLAN_FILTER:
+               return hclge_set_vlan_filter(handle,
+                                            cpu_to_be16(msg_cmd->proto),
+                                            msg_cmd->vlan, msg_cmd->is_kill);
+       case HCLGE_MBX_VLAN_RX_OFF_CFG:
+               return hclge_en_hw_strip_rxvtag(handle, msg_cmd->enable);
+       case HCLGE_MBX_GET_PORT_BASE_VLAN_STATE:
                /* vf does not need to know about the port based VLAN state
                 * on device HNAE3_DEVICE_VERSION_V3. So always return disable
                 * on device HNAE3_DEVICE_VERSION_V3 if vf queries the port
                 * based VLAN state.
                 */
                resp_msg->data[0] =
-                       ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3 ?
+                       hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3 ?
                        HNAE3_PORT_BASE_VLAN_DISABLE :
                        vport->port_base_vlan_cfg.state;
                resp_msg->len = sizeof(u8);
+               return 0;
+       case HCLGE_MBX_ENABLE_VLAN_FILTER:
+               return hclge_enable_vport_vlan_filter(vport, msg_cmd->enable);
+       default:
+               return 0;
        }
-
-       return status;
 }
 
 static int hclge_set_vf_alive(struct hclge_vport *vport,
@@ -400,16 +386,23 @@ static int hclge_set_vf_alive(struct hclge_vport *vport,
        return ret;
 }
 
-static void hclge_get_vf_tcinfo(struct hclge_vport *vport,
-                               struct hclge_respond_to_vf_msg *resp_msg)
+static void hclge_get_basic_info(struct hclge_vport *vport,
+                                struct hclge_respond_to_vf_msg *resp_msg)
 {
        struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
+       struct hnae3_ae_dev *ae_dev = vport->back->ae_dev;
+       struct hclge_basic_info *basic_info;
        unsigned int i;
 
+       basic_info = (struct hclge_basic_info *)resp_msg->data;
        for (i = 0; i < kinfo->tc_info.num_tc; i++)
-               resp_msg->data[0] |= BIT(i);
+               basic_info->hw_tc_map |= BIT(i);
 
-       resp_msg->len = sizeof(u8);
+       if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps))
+               hnae3_set_bit(basic_info->pf_caps,
+                             HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B, 1);
+
+       resp_msg->len = HCLGE_MBX_MAX_RESP_DATA_SIZE;
 }
 
 static void hclge_get_vf_queue_info(struct hclge_vport *vport,
@@ -768,8 +761,8 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
                case HCLGE_MBX_GET_QDEPTH:
                        hclge_get_vf_queue_depth(vport, &resp_msg);
                        break;
-               case HCLGE_MBX_GET_TCINFO:
-                       hclge_get_vf_tcinfo(vport, &resp_msg);
+               case HCLGE_MBX_GET_BASIC_INFO:
+                       hclge_get_basic_info(vport, &resp_msg);
                        break;
                case HCLGE_MBX_GET_LINK_STATUS:
                        ret = hclge_push_vf_link_status(vport);
index 7bef6b2..f84b3a1 100644 (file)
@@ -243,23 +243,31 @@ static void hclgevf_build_send_msg(struct hclge_vf_to_pf_msg *msg, u8 code,
        }
 }
 
-static int hclgevf_get_tc_info(struct hclgevf_dev *hdev)
+static int hclgevf_get_basic_info(struct hclgevf_dev *hdev)
 {
+       struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
+       u8 resp_msg[HCLGE_MBX_MAX_RESP_DATA_SIZE];
+       struct hclge_basic_info *basic_info;
        struct hclge_vf_to_pf_msg send_msg;
-       u8 resp_msg;
+       unsigned long caps;
        int status;
 
-       hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_TCINFO, 0);
-       status = hclgevf_send_mbx_msg(hdev, &send_msg, true, &resp_msg,
+       hclgevf_build_send_msg(&send_msg, HCLGE_MBX_GET_BASIC_INFO, 0);
+       status = hclgevf_send_mbx_msg(hdev, &send_msg, true, resp_msg,
                                      sizeof(resp_msg));
        if (status) {
                dev_err(&hdev->pdev->dev,
-                       "VF request to get TC info from PF failed %d",
-                       status);
+                       "failed to get basic info from pf, ret = %d", status);
                return status;
        }
 
-       hdev->hw_tc_map = resp_msg;
+       basic_info = (struct hclge_basic_info *)resp_msg;
+
+       hdev->hw_tc_map = basic_info->hw_tc_map;
+       hdev->mbx_api_version = basic_info->mbx_api_version;
+       caps = basic_info->pf_caps;
+       if (test_bit(HNAE3_PF_SUPPORT_VLAN_FLTR_MDF_B, &caps))
+               set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps);
 
        return 0;
 }
@@ -1642,6 +1650,22 @@ static void hclgevf_uninit_mac_list(struct hclgevf_dev *hdev)
        spin_unlock_bh(&hdev->mac_table.mac_list_lock);
 }
 
+static int hclgevf_enable_vlan_filter(struct hnae3_handle *handle, bool enable)
+{
+       struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle);
+       struct hnae3_ae_dev *ae_dev = hdev->ae_dev;
+       struct hclge_vf_to_pf_msg send_msg;
+
+       if (!test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps))
+               return -EOPNOTSUPP;
+
+       hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN,
+                              HCLGE_MBX_ENABLE_VLAN_FILTER);
+       send_msg.data[0] = enable ? 1 : 0;
+
+       return hclgevf_send_mbx_msg(hdev, &send_msg, true, NULL, 0);
+}
+
 static int hclgevf_set_vlan_filter(struct hnae3_handle *handle,
                                   __be16 proto, u16 vlan_id,
                                   bool is_kill)
@@ -2466,6 +2490,10 @@ static int hclgevf_configure(struct hclgevf_dev *hdev)
 {
        int ret;
 
+       ret = hclgevf_get_basic_info(hdev);
+       if (ret)
+               return ret;
+
        /* get current port based vlan state from PF */
        ret = hclgevf_get_port_base_vlan_filter_state(hdev);
        if (ret)
@@ -2481,12 +2509,7 @@ static int hclgevf_configure(struct hclgevf_dev *hdev)
        if (ret)
                return ret;
 
-       ret = hclgevf_get_pf_media_type(hdev);
-       if (ret)
-               return ret;
-
-       /* get tc configuration from PF */
-       return hclgevf_get_tc_info(hdev);
+       return hclgevf_get_pf_media_type(hdev);
 }
 
 static int hclgevf_alloc_hdev(struct hnae3_ae_dev *ae_dev)
@@ -3801,6 +3824,7 @@ static const struct hnae3_ae_ops hclgevf_ops = {
        .get_tc_size = hclgevf_get_tc_size,
        .get_fw_version = hclgevf_get_fw_version,
        .set_vlan_filter = hclgevf_set_vlan_filter,
+       .enable_vlan_filter = hclgevf_enable_vlan_filter,
        .enable_hw_strip_rxvtag = hclgevf_en_hw_strip_rxvtag,
        .reset_event = hclgevf_reset_event,
        .set_default_reset_request = hclgevf_set_def_reset_request,
index b146d04..d7d0284 100644 (file)
@@ -285,6 +285,7 @@ struct hclgevf_dev {
        struct semaphore reset_sem;     /* protect reset process */
 
        u32 fw_version;
+       u16 mbx_api_version;
        u16 num_tqps;           /* num task queue pairs of this VF */
 
        u16 alloc_rss_size;     /* allocated RSS task queue */