HNAE3_DBG_CMD_UNKNOWN,
 };
 
+enum hnae3_tc_map_mode {
+       HNAE3_TC_MAP_MODE_PRIO,
+       HNAE3_TC_MAP_MODE_DSCP,
+};
+
 struct hnae3_vector_info {
        u8 __iomem *io_addr;
        int vector;
        int (*get_link_diagnosis_info)(struct hnae3_handle *handle,
                                       u32 *status_code);
        void (*clean_vf_config)(struct hnae3_ae_dev *ae_dev, int num_vfs);
+       int (*get_dscp_prio)(struct hnae3_handle *handle, u8 dscp,
+                            u8 *tc_map_mode, u8 *priority);
 };
 
 struct hnae3_dcb_ops {
        int (*ieee_setets)(struct hnae3_handle *, struct ieee_ets *);
        int (*ieee_getpfc)(struct hnae3_handle *, struct ieee_pfc *);
        int (*ieee_setpfc)(struct hnae3_handle *, struct ieee_pfc *);
+       int (*ieee_setapp)(struct hnae3_handle *h, struct dcb_app *app);
+       int (*ieee_delapp)(struct hnae3_handle *h, struct dcb_app *app);
 
        /* DCBX configuration */
        u8   (*getdcbx)(struct hnae3_handle *);
        u32 tx_spare_buf_size;
 
        struct hnae3_tc_info tc_info;
+       u8 tc_map_mode;
 
        u16 num_tqps;             /* total number of TQPs in this handle */
        struct hnae3_queue **tqp;  /* array base of all TQPs in this instance */
 
        return -EOPNOTSUPP;
 }
 
+static int hns3_dcbnl_ieee_setapp(struct net_device *ndev, struct dcb_app *app)
+{
+       struct hnae3_handle *h = hns3_get_handle(ndev);
+
+       if (hns3_nic_resetting(ndev))
+               return -EBUSY;
+
+       if (h->kinfo.dcb_ops->ieee_setapp)
+               return h->kinfo.dcb_ops->ieee_setapp(h, app);
+
+       return -EOPNOTSUPP;
+}
+
+static int hns3_dcbnl_ieee_delapp(struct net_device *ndev, struct dcb_app *app)
+{
+       struct hnae3_handle *h = hns3_get_handle(ndev);
+
+       if (hns3_nic_resetting(ndev))
+               return -EBUSY;
+
+       if (h->kinfo.dcb_ops->ieee_setapp)
+               return h->kinfo.dcb_ops->ieee_delapp(h, app);
+
+       return -EOPNOTSUPP;
+}
+
 /* DCBX configuration */
 static u8 hns3_dcbnl_getdcbx(struct net_device *ndev)
 {
        .ieee_setets    = hns3_dcbnl_ieee_setets,
        .ieee_getpfc    = hns3_dcbnl_ieee_getpfc,
        .ieee_setpfc    = hns3_dcbnl_ieee_setpfc,
+       .ieee_setapp    = hns3_dcbnl_ieee_setapp,
+       .ieee_delapp    = hns3_dcbnl_ieee_delapp,
        .getdcbx        = hns3_dcbnl_getdcbx,
        .setdcbx        = hns3_dcbnl_setdcbx,
 };
 
        return hclge_notify_client(hdev, HNAE3_UP_CLIENT);
 }
 
+static int hclge_ieee_setapp(struct hnae3_handle *h, struct dcb_app *app)
+{
+       struct hclge_vport *vport = hclge_get_vport(h);
+       struct net_device *netdev = h->kinfo.netdev;
+       struct hclge_dev *hdev = vport->back;
+       struct dcb_app old_app;
+       int ret;
+
+       if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP ||
+           app->protocol >= HCLGE_MAX_DSCP ||
+           app->priority >= HNAE3_MAX_USER_PRIO)
+               return -EINVAL;
+
+       dev_info(&hdev->pdev->dev, "setapp dscp=%u priority=%u\n",
+                app->protocol, app->priority);
+
+       if (app->priority == hdev->tm_info.dscp_prio[app->protocol])
+               return 0;
+
+       ret = dcb_ieee_setapp(netdev, app);
+       if (ret)
+               return ret;
+
+       old_app.selector = IEEE_8021QAZ_APP_SEL_DSCP;
+       old_app.protocol = app->protocol;
+       old_app.priority = hdev->tm_info.dscp_prio[app->protocol];
+
+       hdev->tm_info.dscp_prio[app->protocol] = app->priority;
+       ret = hclge_dscp_to_tc_map(hdev);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "failed to set dscp to tc map, ret = %d\n", ret);
+               hdev->tm_info.dscp_prio[app->protocol] = old_app.priority;
+               (void)dcb_ieee_delapp(netdev, app);
+               return ret;
+       }
+
+       vport->nic.kinfo.tc_map_mode = HNAE3_TC_MAP_MODE_DSCP;
+       if (old_app.priority == HCLGE_PRIO_ID_INVALID)
+               hdev->tm_info.dscp_app_cnt++;
+       else
+               ret = dcb_ieee_delapp(netdev, &old_app);
+
+       return ret;
+}
+
+static int hclge_ieee_delapp(struct hnae3_handle *h, struct dcb_app *app)
+{
+       struct hclge_vport *vport = hclge_get_vport(h);
+       struct net_device *netdev = h->kinfo.netdev;
+       struct hclge_dev *hdev = vport->back;
+       int ret;
+
+       if (app->selector != IEEE_8021QAZ_APP_SEL_DSCP ||
+           app->protocol >= HCLGE_MAX_DSCP ||
+           app->priority >= HNAE3_MAX_USER_PRIO ||
+           app->priority != hdev->tm_info.dscp_prio[app->protocol])
+               return -EINVAL;
+
+       dev_info(&hdev->pdev->dev, "delapp dscp=%u priority=%u\n",
+                app->protocol, app->priority);
+
+       ret = dcb_ieee_delapp(netdev, app);
+       if (ret)
+               return ret;
+
+       hdev->tm_info.dscp_prio[app->protocol] = HCLGE_PRIO_ID_INVALID;
+       ret = hclge_dscp_to_tc_map(hdev);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "failed to del dscp to tc map, ret = %d\n", ret);
+               hdev->tm_info.dscp_prio[app->protocol] = app->priority;
+               (void)dcb_ieee_setapp(netdev, app);
+               return ret;
+       }
+
+       if (hdev->tm_info.dscp_app_cnt)
+               hdev->tm_info.dscp_app_cnt--;
+
+       if (!hdev->tm_info.dscp_app_cnt) {
+               vport->nic.kinfo.tc_map_mode = HNAE3_TC_MAP_MODE_PRIO;
+               ret = hclge_up_to_tc_map(hdev);
+       }
+
+       return ret;
+}
+
 /* DCBX configuration */
 static u8 hclge_getdcbx(struct hnae3_handle *h)
 {
        .ieee_setets    = hclge_ieee_setets,
        .ieee_getpfc    = hclge_ieee_getpfc,
        .ieee_setpfc    = hclge_ieee_setpfc,
+       .ieee_setapp    = hclge_ieee_setapp,
+       .ieee_delapp    = hclge_ieee_delapp,
        .getdcbx        = hclge_getdcbx,
        .setdcbx        = hclge_setdcbx,
        .setup_tc       = hclge_setup_tc,
 
        }
 }
 
+static int hclge_get_dscp_prio(struct hnae3_handle *h, u8 dscp, u8 *tc_mode,
+                              u8 *priority)
+{
+       struct hclge_vport *vport = hclge_get_vport(h);
+       struct hclge_dev *hdev = vport->back;
+
+       if (dscp >= HCLGE_MAX_DSCP)
+               return -EINVAL;
+
+       if (tc_mode)
+               *tc_mode = vport->nic.kinfo.tc_map_mode;
+       if (priority)
+               *priority = hdev->tm_info.dscp_prio[dscp] == HCLGE_PRIO_ID_INVALID ? 0 :
+                           hdev->tm_info.dscp_prio[dscp];
+
+       return 0;
+}
+
 static const struct hnae3_ae_ops hclge_ops = {
        .init_ae_dev = hclge_init_ae_dev,
        .uninit_ae_dev = hclge_uninit_ae_dev,
        .get_ts_info = hclge_ptp_get_ts_info,
        .get_link_diagnosis_info = hclge_get_link_diagnosis_info,
        .clean_vf_config = hclge_clean_vport_config,
+       .get_dscp_prio = hclge_get_dscp_prio,
 };
 
 static struct hnae3_ae_algo ae_algo = {
 
        u16 umv_space;
 };
 
+#define HCLGE_MAX_DSCP                 64
+#define HCLGE_PRIO_ID_INVALID          0xff
 struct hclge_tm_info {
        u8 num_tc;
        u8 num_pg;      /* It must be 1 if vNET-Base schd */
+       u8 dscp_app_cnt;
        u8 pg_dwrr[HCLGE_PG_NUM];
        u8 prio_tc[HNAE3_MAX_USER_PRIO];
+       u8 dscp_prio[HCLGE_MAX_DSCP];
        struct hclge_pg_info pg_info[HCLGE_PG_NUM];
        struct hclge_tc_info tc_info[HNAE3_MAX_TC];
        enum hclge_fc_mode fc_mode;
 
        return 0;
 }
 
-static int hclge_up_to_tc_map(struct hclge_dev *hdev)
+int hclge_up_to_tc_map(struct hclge_dev *hdev)
 {
        struct hclge_desc desc;
        u8 *pri = (u8 *)desc.data;
        return hclge_cmd_send(&hdev->hw, &desc, 1);
 }
 
+static void hclge_dscp_to_prio_map_init(struct hclge_dev *hdev)
+{
+       u8 i;
+
+       hdev->vport[0].nic.kinfo.tc_map_mode = HNAE3_TC_MAP_MODE_PRIO;
+       hdev->tm_info.dscp_app_cnt = 0;
+       for (i = 0; i < HCLGE_MAX_DSCP; i++)
+               hdev->tm_info.dscp_prio[i] = HCLGE_PRIO_ID_INVALID;
+}
+
+int hclge_dscp_to_tc_map(struct hclge_dev *hdev)
+{
+       struct hclge_desc desc[HCLGE_DSCP_MAP_TC_BD_NUM];
+       u8 *req0 = (u8 *)desc[0].data;
+       u8 *req1 = (u8 *)desc[1].data;
+       u8 pri_id, tc_id, i, j;
+
+       hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QOS_MAP, false);
+       desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
+       hclge_cmd_setup_basic_desc(&desc[1], HCLGE_OPC_QOS_MAP, false);
+
+       /* The low 32 dscp setting use bd0, high 32 dscp setting use bd1 */
+       for (i = 0; i < HCLGE_MAX_DSCP / HCLGE_DSCP_MAP_TC_BD_NUM; i++) {
+               pri_id = hdev->tm_info.dscp_prio[i];
+               pri_id = pri_id == HCLGE_PRIO_ID_INVALID ? 0 : pri_id;
+               tc_id = hdev->tm_info.prio_tc[pri_id];
+               /* Each dscp setting has 4 bits, so each byte saves two dscp
+                * setting
+                */
+               req0[i >> 1] |= tc_id << HCLGE_DSCP_TC_SHIFT(i);
+
+               j = i + HCLGE_MAX_DSCP / HCLGE_DSCP_MAP_TC_BD_NUM;
+               pri_id = hdev->tm_info.dscp_prio[j];
+               pri_id = pri_id == HCLGE_PRIO_ID_INVALID ? 0 : pri_id;
+               tc_id = hdev->tm_info.prio_tc[pri_id];
+               req1[i >> 1] |= tc_id << HCLGE_DSCP_TC_SHIFT(i);
+       }
+
+       return hclge_cmd_send(&hdev->hw, desc, HCLGE_DSCP_MAP_TC_BD_NUM);
+}
+
 static int hclge_tm_pg_to_pri_map_cfg(struct hclge_dev *hdev,
                                      u8 pg_id, u8 pri_bit_map)
 {
        if (ret)
                return ret;
 
+       if (hdev->vport[0].nic.kinfo.tc_map_mode == HNAE3_TC_MAP_MODE_DSCP) {
+               ret = hclge_dscp_to_tc_map(hdev);
+               if (ret)
+                       return ret;
+       }
+
        ret = hclge_tm_pg_to_pri_map(hdev);
        if (ret)
                return ret;
                return -EINVAL;
 
        hclge_tm_schd_info_init(hdev);
+       hclge_dscp_to_prio_map_init(hdev);
 
        return hclge_tm_init_hw(hdev, true);
 }
 
 #define HCLGE_TM_PF_MAX_PRI_NUM                8
 #define HCLGE_TM_PF_MAX_QSET_NUM       8
 
+#define HCLGE_DSCP_MAP_TC_BD_NUM       2
+#define HCLGE_DSCP_TC_SHIFT(n)         (((n) & 1) * 4)
+
 struct hclge_pg_to_pri_link_cmd {
        u8 pg_id;
        u8 rsvd1[3];
                           struct hclge_tm_shaper_para *para);
 int hclge_tm_get_port_shaper(struct hclge_dev *hdev,
                             struct hclge_tm_shaper_para *para);
+int hclge_up_to_tc_map(struct hclge_dev *hdev);
+int hclge_dscp_to_tc_map(struct hclge_dev *hdev);
 #endif