HCLGE_OPC_VLAN_FILTER_PF_CFG    = 0x1101,
        HCLGE_OPC_VLAN_FILTER_VF_CFG    = 0x1102,
 
+       /* Flow Director commands */
+       HCLGE_OPC_FD_MODE_CTRL          = 0x1200,
+       HCLGE_OPC_FD_GET_ALLOCATION     = 0x1201,
+       HCLGE_OPC_FD_KEY_CONFIG         = 0x1202,
+
        /* MDIO command */
        HCLGE_OPC_MDIO_CONFIG           = 0x1900,
 
        u8 rsv2[20];
 };
 
+struct hclge_get_fd_mode_cmd {
+       u8 mode;
+       u8 enable;
+       u8 rsv[22];
+};
+
+struct hclge_get_fd_allocation_cmd {
+       __le32 stage1_entry_num;
+       __le32 stage2_entry_num;
+       __le16 stage1_counter_num;
+       __le16 stage2_counter_num;
+       u8 rsv[12];
+};
+
+struct hclge_set_fd_key_config_cmd {
+       u8 stage;
+       u8 key_select;
+       u8 inner_sipv6_word_en;
+       u8 inner_dipv6_word_en;
+       u8 outer_sipv6_word_en;
+       u8 outer_dipv6_word_en;
+       u8 rsv1[2];
+       __le32 tuple_mask;
+       __le32 meta_data_mask;
+       u8 rsv2[8];
+};
+
 int hclge_cmd_init(struct hclge_dev *hdev);
 static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
 {
 
        hclge_cmd_set_promisc_mode(hdev, ¶m);
 }
 
+static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode)
+{
+       struct hclge_get_fd_mode_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_MODE_CTRL, true);
+
+       req = (struct hclge_get_fd_mode_cmd *)desc.data;
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev, "get fd mode fail, ret=%d\n", ret);
+               return ret;
+       }
+
+       *fd_mode = req->mode;
+
+       return ret;
+}
+
+static int hclge_get_fd_allocation(struct hclge_dev *hdev,
+                                  u32 *stage1_entry_num,
+                                  u32 *stage2_entry_num,
+                                  u16 *stage1_counter_num,
+                                  u16 *stage2_counter_num)
+{
+       struct hclge_get_fd_allocation_cmd *req;
+       struct hclge_desc desc;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_GET_ALLOCATION, true);
+
+       req = (struct hclge_get_fd_allocation_cmd *)desc.data;
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev, "query fd allocation fail, ret=%d\n",
+                       ret);
+               return ret;
+       }
+
+       *stage1_entry_num = le32_to_cpu(req->stage1_entry_num);
+       *stage2_entry_num = le32_to_cpu(req->stage2_entry_num);
+       *stage1_counter_num = le16_to_cpu(req->stage1_counter_num);
+       *stage2_counter_num = le16_to_cpu(req->stage2_counter_num);
+
+       return ret;
+}
+
+static int hclge_set_fd_key_config(struct hclge_dev *hdev, int stage_num)
+{
+       struct hclge_set_fd_key_config_cmd *req;
+       struct hclge_fd_key_cfg *stage;
+       struct hclge_desc desc;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_FD_KEY_CONFIG, false);
+
+       req = (struct hclge_set_fd_key_config_cmd *)desc.data;
+       stage = &hdev->fd_cfg.key_cfg[stage_num];
+       req->stage = stage_num;
+       req->key_select = stage->key_sel;
+       req->inner_sipv6_word_en = stage->inner_sipv6_word_en;
+       req->inner_dipv6_word_en = stage->inner_dipv6_word_en;
+       req->outer_sipv6_word_en = stage->outer_sipv6_word_en;
+       req->outer_dipv6_word_en = stage->outer_dipv6_word_en;
+       req->tuple_mask = cpu_to_le32(~stage->tuple_active);
+       req->meta_data_mask = cpu_to_le32(~stage->meta_data_active);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret)
+               dev_err(&hdev->pdev->dev, "set fd key fail, ret=%d\n", ret);
+
+       return ret;
+}
+
+static int hclge_init_fd_config(struct hclge_dev *hdev)
+{
+#define LOW_2_WORDS            0x03
+       struct hclge_fd_key_cfg *key_cfg;
+       int ret;
+
+       if (!hnae3_dev_fd_supported(hdev))
+               return 0;
+
+       ret = hclge_get_fd_mode(hdev, &hdev->fd_cfg.fd_mode);
+       if (ret)
+               return ret;
+
+       switch (hdev->fd_cfg.fd_mode) {
+       case HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1:
+               hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH;
+               break;
+       case HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1:
+               hdev->fd_cfg.max_key_length = MAX_KEY_LENGTH / 2;
+               break;
+       default:
+               dev_err(&hdev->pdev->dev,
+                       "Unsupported flow director mode %d\n",
+                       hdev->fd_cfg.fd_mode);
+               return -EOPNOTSUPP;
+       }
+
+       hdev->fd_cfg.fd_en = true;
+       hdev->fd_cfg.proto_support =
+               TCP_V4_FLOW | UDP_V4_FLOW | SCTP_V4_FLOW | TCP_V6_FLOW |
+               UDP_V6_FLOW | SCTP_V6_FLOW | IPV4_USER_FLOW | IPV6_USER_FLOW;
+       key_cfg = &hdev->fd_cfg.key_cfg[HCLGE_FD_STAGE_1];
+       key_cfg->key_sel = HCLGE_FD_KEY_BASE_ON_TUPLE,
+       key_cfg->inner_sipv6_word_en = LOW_2_WORDS;
+       key_cfg->inner_dipv6_word_en = LOW_2_WORDS;
+       key_cfg->outer_sipv6_word_en = 0;
+       key_cfg->outer_dipv6_word_en = 0;
+
+       key_cfg->tuple_active = BIT(INNER_VLAN_TAG_FST) | BIT(INNER_ETH_TYPE) |
+                               BIT(INNER_IP_PROTO) | BIT(INNER_IP_TOS) |
+                               BIT(INNER_SRC_IP) | BIT(INNER_DST_IP) |
+                               BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT);
+
+       /* If use max 400bit key, we can support tuples for ether type */
+       if (hdev->fd_cfg.max_key_length == MAX_KEY_LENGTH) {
+               hdev->fd_cfg.proto_support |= ETHER_FLOW;
+               key_cfg->tuple_active |=
+                               BIT(INNER_DST_MAC) | BIT(INNER_SRC_MAC);
+       }
+
+       /* roce_type is used to filter roce frames
+        * dst_vport is used to specify the rule
+        */
+       key_cfg->meta_data_active = BIT(ROCE_TYPE) | BIT(DST_VPORT);
+
+       ret = hclge_get_fd_allocation(hdev,
+                                     &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1],
+                                     &hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_2],
+                                     &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_1],
+                                     &hdev->fd_cfg.cnt_num[HCLGE_FD_STAGE_2]);
+       if (ret)
+               return ret;
+
+       return hclge_set_fd_key_config(hdev, HCLGE_FD_STAGE_1);
+}
+
 static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
 {
        struct hclge_desc desc;
                goto err_mdiobus_unreg;
        }
 
+       ret = hclge_init_fd_config(hdev);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "fd table init fail, ret=%d\n", ret);
+               goto err_mdiobus_unreg;
+       }
+
        hclge_dcb_ops_set(hdev);
 
        timer_setup(&hdev->service_timer, hclge_service_timer, 0);
                return ret;
        }
 
+       ret = hclge_init_fd_config(hdev);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "fd table init fail, ret=%d\n", ret);
+               return ret;
+       }
+
        dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
                 HCLGE_DRIVER_NAME);
 
 
        u16 tx_in_vlan_type;
 };
 
+enum HCLGE_FD_MODE {
+       HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1,
+       HCLGE_FD_MODE_DEPTH_1K_WIDTH_400B_STAGE_2,
+       HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1,
+       HCLGE_FD_MODE_DEPTH_2K_WIDTH_200B_STAGE_2,
+};
+
+enum HCLGE_FD_KEY_TYPE {
+       HCLGE_FD_KEY_BASE_ON_PTYPE,
+       HCLGE_FD_KEY_BASE_ON_TUPLE,
+};
+
+enum HCLGE_FD_STAGE {
+       HCLGE_FD_STAGE_1,
+       HCLGE_FD_STAGE_2,
+};
+
+/* OUTER_XXX indicates tuples in tunnel header of tunnel packet
+ * INNER_XXX indicate tuples in tunneled header of tunnel packet or
+ *           tuples of non-tunnel packet
+ */
+enum HCLGE_FD_TUPLE {
+       OUTER_DST_MAC,
+       OUTER_SRC_MAC,
+       OUTER_VLAN_TAG_FST,
+       OUTER_VLAN_TAG_SEC,
+       OUTER_ETH_TYPE,
+       OUTER_L2_RSV,
+       OUTER_IP_TOS,
+       OUTER_IP_PROTO,
+       OUTER_SRC_IP,
+       OUTER_DST_IP,
+       OUTER_L3_RSV,
+       OUTER_SRC_PORT,
+       OUTER_DST_PORT,
+       OUTER_L4_RSV,
+       OUTER_TUN_VNI,
+       OUTER_TUN_FLOW_ID,
+       INNER_DST_MAC,
+       INNER_SRC_MAC,
+       INNER_VLAN_TAG_FST,
+       INNER_VLAN_TAG_SEC,
+       INNER_ETH_TYPE,
+       INNER_L2_RSV,
+       INNER_IP_TOS,
+       INNER_IP_PROTO,
+       INNER_SRC_IP,
+       INNER_DST_IP,
+       INNER_L3_RSV,
+       INNER_SRC_PORT,
+       INNER_DST_PORT,
+       INNER_L4_RSV,
+       MAX_TUPLE,
+};
+
+enum HCLGE_FD_META_DATA {
+       PACKET_TYPE_ID,
+       IP_FRAGEMENT,
+       ROCE_TYPE,
+       NEXT_KEY,
+       VLAN_NUMBER,
+       SRC_VPORT,
+       DST_VPORT,
+       TUNNEL_PACKET,
+       MAX_META_DATA,
+};
+
+struct key_info {
+       u8 key_type;
+       u8 key_length;
+};
+
+static const struct key_info meta_data_key_info[] = {
+       { PACKET_TYPE_ID, 6},
+       { IP_FRAGEMENT, 1},
+       { ROCE_TYPE, 1},
+       { NEXT_KEY, 5},
+       { VLAN_NUMBER, 2},
+       { SRC_VPORT, 12},
+       { DST_VPORT, 12},
+       { TUNNEL_PACKET, 1},
+};
+
+static const struct key_info tuple_key_info[] = {
+       { OUTER_DST_MAC, 48},
+       { OUTER_SRC_MAC, 48},
+       { OUTER_VLAN_TAG_FST, 16},
+       { OUTER_VLAN_TAG_SEC, 16},
+       { OUTER_ETH_TYPE, 16},
+       { OUTER_L2_RSV, 16},
+       { OUTER_IP_TOS, 8},
+       { OUTER_IP_PROTO, 8},
+       { OUTER_SRC_IP, 32},
+       { OUTER_DST_IP, 32},
+       { OUTER_L3_RSV, 16},
+       { OUTER_SRC_PORT, 16},
+       { OUTER_DST_PORT, 16},
+       { OUTER_L4_RSV, 32},
+       { OUTER_TUN_VNI, 24},
+       { OUTER_TUN_FLOW_ID, 8},
+       { INNER_DST_MAC, 48},
+       { INNER_SRC_MAC, 48},
+       { INNER_VLAN_TAG_FST, 16},
+       { INNER_VLAN_TAG_SEC, 16},
+       { INNER_ETH_TYPE, 16},
+       { INNER_L2_RSV, 16},
+       { INNER_IP_TOS, 8},
+       { INNER_IP_PROTO, 8},
+       { INNER_SRC_IP, 32},
+       { INNER_DST_IP, 32},
+       { INNER_L3_RSV, 16},
+       { INNER_SRC_PORT, 16},
+       { INNER_DST_PORT, 16},
+       { INNER_L4_RSV, 32},
+};
+
+#define MAX_KEY_LENGTH 400
+#define MAX_KEY_DWORDS DIV_ROUND_UP(MAX_KEY_LENGTH / 8, 4)
+#define MAX_KEY_BYTES  (MAX_KEY_DWORDS * 4)
+#define MAX_META_DATA_LENGTH   32
+
+enum HCLGE_FD_PACKET_TYPE {
+       NIC_PACKET,
+       ROCE_PACKET,
+};
+
+struct hclge_fd_key_cfg {
+       u8 key_sel;
+       u8 inner_sipv6_word_en;
+       u8 inner_dipv6_word_en;
+       u8 outer_sipv6_word_en;
+       u8 outer_dipv6_word_en;
+       u32 tuple_active;
+       u32 meta_data_active;
+};
+
+struct hclge_fd_cfg {
+       u8 fd_mode;
+       u8 fd_en;
+       u16 max_key_length;
+       u32 proto_support;
+       u32 rule_num[2]; /* rule entry number */
+       u16 cnt_num[2]; /* rule hit counter number */
+       struct hclge_fd_key_cfg key_cfg[2];
+};
+
 #define HCLGE_VPORT_NUM 256
 struct hclge_dev {
        struct pci_dev *pdev;
        struct hclge_vlan_type_cfg vlan_type_cfg;
 
        unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)];
+
+       struct hclge_fd_cfg fd_cfg;
 };
 
 /* VPort level vlan tag configuration for TX direction */