diff mbox series

[net-next,2/2] net: hns3: PF add support setting parameters of congestion control algorithm by devlink param

Message ID 20220923013818.51003-3-huangguangbin2@huawei.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series net: hns3: add support setting parameters of congestion control algorithm by devlink param | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 1 this patch: 15
netdev/cc_maintainers warning 1 maintainers not CCed: leon@kernel.org
netdev/build_clang fail Errors and warnings before: 0 this patch: 4
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 0 this patch: 10
netdev/checkpatch warning WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Guangbin Huang Sept. 23, 2022, 1:38 a.m. UTC
From: Hao Chen <chenhao418@huawei.com>

Some new devices support dynamiclly configuring parameters of congestion
control algorithm, this patch implement it by devlink param.

Examples of read and set command are as follows:

$ devlink dev param set pci/0000:35:00.0 name algo_param value \
  "type@dcqcn_alp@30_f@35_tmp@11_tkp@11_ai@60_maxspeed@17_g@11_al@19_cnptime@20" \
  cmode runtime

$ devlink dev param show pci/0000:35:00.0 name algo_param
pci/0000:35:00.0:
  name algo_param type driver-specific
    values:
      cmode runtime value type@dcqcn_ai@60_f@35_tkp@11_tmp@11_alp@30_maxspeed@17_g@11_al@19_cnptime@20

Signed-off-by: Hao Chen <chenhao418@huawei.com>
Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
---
 .../hns3/hns3_common/hclge_comm_cmd.h         |   6 +
 .../hisilicon/hns3/hns3pf/hclge_cmd.h         |  44 +
 .../hisilicon/hns3/hns3pf/hclge_devlink.c     | 788 ++++++++++++++++++
 .../hisilicon/hns3/hns3pf/hclge_devlink.h     |   6 +
 .../hisilicon/hns3/hns3pf/hclge_main.c        | 122 +++
 .../hisilicon/hns3/hns3pf/hclge_main.h        |  61 ++
 6 files changed, 1027 insertions(+)

Comments

Jakub Kicinski Sept. 23, 2022, 2:23 a.m. UTC | #1
On Fri, 23 Sep 2022 09:38:18 +0800 Guangbin Huang wrote:
> Some new devices support dynamiclly configuring parameters of congestion
> control algorithm, this patch implement it by devlink param.
> 
> Examples of read and set command are as follows:
> 
> $ devlink dev param set pci/0000:35:00.0 name algo_param value \
>   "type@dcqcn_alp@30_f@35_tmp@11_tkp@11_ai@60_maxspeed@17_g@11_al@19_cnptime@20" \
>   cmode runtime
> 
> $ devlink dev param show pci/0000:35:00.0 name algo_param
> pci/0000:35:00.0:
>   name algo_param type driver-specific
>     values:
>       cmode runtime value type@dcqcn_ai@60_f@35_tkp@11_tmp@11_alp@30_maxspeed@17_g@11_al@19_cnptime@20

Please put your RDMA params to the RDMA subsystem.
It's not what devlink is for. In general 95% of the time devlink params
are not the answer upstream.
Guangbin Huang Sept. 23, 2022, 2:39 a.m. UTC | #2
On 2022/9/23 10:23, Jakub Kicinski wrote:
> On Fri, 23 Sep 2022 09:38:18 +0800 Guangbin Huang wrote:
>> Some new devices support dynamiclly configuring parameters of congestion
>> control algorithm, this patch implement it by devlink param.
>>
>> Examples of read and set command are as follows:
>>
>> $ devlink dev param set pci/0000:35:00.0 name algo_param value \
>>    "type@dcqcn_alp@30_f@35_tmp@11_tkp@11_ai@60_maxspeed@17_g@11_al@19_cnptime@20" \
>>    cmode runtime
>>
>> $ devlink dev param show pci/0000:35:00.0 name algo_param
>> pci/0000:35:00.0:
>>    name algo_param type driver-specific
>>      values:
>>        cmode runtime value type@dcqcn_ai@60_f@35_tkp@11_tmp@11_alp@30_maxspeed@17_g@11_al@19_cnptime@20
> 
> Please put your RDMA params to the RDMA subsystem.
> It's not what devlink is for. In general 95% of the time devlink params
> are not the answer upstream.
> .
> 
Ok, I will discuss with our team.
kernel test robot Sept. 23, 2022, 11:20 a.m. UTC | #3
Hi Guangbin,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Guangbin-Huang/net-hns3-add-support-setting-parameters-of-congestion-control-algorithm-by-devlink-param/20220923-094236
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git bcff1a37bafc144d67192f2f5e1f4b9c49b37bd6
config: s390-allyesconfig (https://download.01.org/0day-ci/archive/20220923/202209231935.JRvKASjh-lkp@intel.com/config)
compiler: s390-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/fc0ab8f22c924e963b0e0a2723cbb49acc1d3bb3
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Guangbin-Huang/net-hns3-add-support-setting-parameters-of-congestion-control-algorithm-by-devlink-param/20220923-094236
        git checkout fc0ab8f22c924e963b0e0a2723cbb49acc1d3bb3
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bash drivers/net/ethernet/hisilicon/hns3/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c: In function 'hclge_devlink_get_algo_param_value':
>> drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c:418:35: warning: variable 'tmp' set but not used [-Wunused-but-set-variable]
     418 |         char *value, *value_tmp, *tmp;
         |                                   ^~~
   drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c: In function 'hclge_devlink_algo_param_set':
>> drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c:690:13: warning: variable 'cnt' set but not used [-Wunused-but-set-variable]
     690 |         int cnt = 0;
         |             ^~~
   drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c: In function 'hclge_devlink_is_algo_param_valid':
   drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c:727:35: warning: variable 'tmp' set but not used [-Wunused-but-set-variable]
     727 |         char *value, *value_tmp, *tmp;
         |                                   ^~~


vim +/tmp +418 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c

   415	
   416	static int hclge_devlink_get_algo_param_value(const char *str, u64 *param_value)
   417	{
 > 418		char *value, *value_tmp, *tmp;
   419		int ret = 0;
   420		int i;
   421	
   422		value = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
   423				GFP_KERNEL);
   424		if (!value)
   425			return -ENOMEM;
   426	
   427		strncpy(value, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
   428		value_tmp = value;
   429	
   430		tmp = strsep(&value, "@");
   431	
   432		for (i = 0; i < strlen(value); i++) {
   433			if (!(value[i] >= '0' && value[i] <= '9')) {
   434				kfree(value_tmp);
   435				return -EINVAL;
   436			}
   437		}
   438	
   439		ret = kstrtou64(value, 0, param_value);
   440	
   441		kfree(value_tmp);
   442		return ret;
   443	}
   444
diff mbox series

Patch

diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h
index b1f9383b418f..8ee477a39d4a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h
@@ -243,6 +243,12 @@  enum hclge_opcode_type {
 	HCLGE_OPC_QCN_AJUST_INIT	= 0x1A07,
 	HCLGE_OPC_QCN_DFX_CNT_STATUS    = 0x1A08,
 
+	/* Algo param commands */
+	HCLGE_OPC_ALGO_PARAM_DCQCN	= 0x1A80,
+	HCLGE_OPC_ALGO_PARAM_LDCP	= 0x1A81,
+	HCLGE_OPC_ALGO_PARAM_HC3	= 0x1A82,
+	HCLGE_OPC_ALGO_PARAM_DIP	= 0x1A83,
+
 	/* Mailbox command */
 	HCLGEVF_OPC_MBX_PF_TO_VF	= 0x2000,
 	HCLGEVF_OPC_MBX_VF_TO_PF	= 0x2001,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index 43cada51d8cb..e19d0da6ae35 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -872,6 +872,50 @@  struct hclge_phy_reg_cmd {
 	u8 rsv1[18];
 };
 
+struct hclge_dcqcn_param_cfg_cmd {
+	__le16 ai;
+	u8 f;
+	u8 tkp;
+	__le16 tmp;
+	__le16 alp;
+	__le32 max_speed;
+	u8 g;
+	u8 al;
+	u8 cnp_time;
+	u8 alp_shift;
+};
+
+struct hclge_ldcp_param_cfg_cmd {
+	__le32 cwd0;
+	u8 la;
+	u8 ly;
+	u8 lb;
+	u8 lg;
+};
+
+struct hclge_hc3_param_cfg_cmd {
+	__le32 win;
+	__le32 hcb;
+	u8 maxqs;
+	u8 hcalp;
+	u8 hct;
+	u8 maxstg;
+	u8 gamshift;
+};
+
+struct hclge_dip_param_cfg_cmd {
+	__le16 ai;
+	u8 f;
+	u8 tkp;
+	__le16 tmp;
+	__le16 alp;
+	__le32 max_speed;
+	u8 g;
+	u8 al;
+	u8 cnp_time;
+	u8 alp_shift;
+};
+
 struct hclge_hw;
 int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num);
 enum hclge_comm_cmd_status hclge_cmd_mdio_write(struct hclge_hw *hw,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c
index 4c441e6a5082..699c433fdf4a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.c
@@ -5,6 +5,9 @@ 
 
 #include "hclge_devlink.h"
 
+#define HCLGE_DEVLINK_MAX_ALGO_TYPE_LEN		16
+#define HCLGE_DEVLINK_MAX_ALGO_PARAM_NUM	12
+
 static int hclge_devlink_info_get(struct devlink *devlink,
 				  struct devlink_info_req *req,
 				  struct netlink_ext_ack *extack)
@@ -97,6 +100,751 @@  static int hclge_devlink_reload_up(struct devlink *devlink,
 	}
 }
 
+static void
+hclge_devlink_dcqcn_param_get(struct devlink *devlink,
+			      struct devlink_param_gset_ctx *ctx, char *type)
+{
+#define DCQCN_ALL_PARAM_STRING \
+	"type@%s_ai@%u_f@%u_tkp@%u_tmp@%u_alp@%u_maxspeed@%u_g@%u_al@%u_cnptime@%u_alpshift@%u\n"
+
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	struct hclge_dev *hdev = priv->hdev;
+	struct hclge_cfg_dcqcn_param *param = &hdev->algo_param.dcqcn_param;
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+
+	scnprintf(str, __DEVLINK_PARAM_MAX_STRING_VALUE, DCQCN_ALL_PARAM_STRING,
+		  type, param->ai, param->f, param->tkp, param->tmp, param->alp,
+		  param->max_speed, param->g, param->al, param->cnp_time,
+		  param->alp_shift);
+	strncpy(ctx->val.vstr, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
+}
+
+static void
+hclge_devlink_ldcp_param_get(struct devlink *devlink,
+			     struct devlink_param_gset_ctx *ctx, char *type)
+{
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	struct hclge_dev *hdev = priv->hdev;
+	struct hclge_cfg_ldcp_param *param = &hdev->algo_param.ldcp_param;
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+
+	scnprintf(str, __DEVLINK_PARAM_MAX_STRING_VALUE,
+		  "type@%s_cwd0@%u_la@%u_ly@%u_lb@%u_lg@%u\n", type,
+		  param->cwd0, param->la, param->ly, param->lb, param->lg);
+	strncpy(ctx->val.vstr, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
+}
+
+static void
+hclge_devlink_hc3_param_get(struct devlink *devlink,
+			    struct devlink_param_gset_ctx *ctx, char *type)
+{
+#define HC3_ALL_PARAM_STRING \
+	"type@%s_win@%u_hcb@%u_maxqs@%u_hcalp@%u_hct@%u_maxstg@%u_gamshift@%u\n"
+
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	struct hclge_dev *hdev = priv->hdev;
+	struct hclge_cfg_hc3_param *param = &hdev->algo_param.hc3_param;
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+
+	scnprintf(str, __DEVLINK_PARAM_MAX_STRING_VALUE, HC3_ALL_PARAM_STRING,
+		  type, param->win, param->hcb, param->maxqs, param->hcalp,
+		  param->hct, param->maxstg, param->gamshift);
+	strncpy(ctx->val.vstr, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
+}
+
+static void
+hclge_devlink_dip_param_get(struct devlink *devlink,
+			    struct devlink_param_gset_ctx *ctx, char *type)
+{
+#define DIP_ALL_PARAM_STRING \
+	"type@%s_ai@%u_f@%u_tkp@%u_tmp@%u_alp@%u_maxspeed@%u_g@%u_al@%u_cnptime@%u_alpshift@%u\n"
+
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	struct hclge_dev *hdev = priv->hdev;
+	struct hclge_cfg_dip_param *param = &hdev->algo_param.dip_param;
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+
+	scnprintf(str, __DEVLINK_PARAM_MAX_STRING_VALUE, DIP_ALL_PARAM_STRING,
+		  type, param->ai, param->f, param->tkp, param->tmp, param->alp,
+		  param->max_speed, param->g, param->al, param->cnp_time,
+		  param->alp_shift);
+	strncpy(ctx->val.vstr, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
+}
+
+static int
+hclge_devlink_algo_param_get(struct devlink *devlink, u32 id,
+			     struct devlink_param_gset_ctx *ctx)
+{
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	char type[HCLGE_DEVLINK_MAX_ALGO_TYPE_LEN] = {0};
+	struct hclge_dev *hdev = priv->hdev;
+
+	switch (hdev->algo_param_type) {
+	case HCLGE_ALGO_PARAM_DCQCN:
+		strncpy(type, "dcqcn", strlen("dcqcn") + 1);
+		hclge_devlink_dcqcn_param_get(devlink, ctx, type);
+		break;
+	case HCLGE_ALGO_PARAM_LDCP:
+		strncpy(type, "ldcp", strlen("ldcp") + 1);
+		hclge_devlink_ldcp_param_get(devlink, ctx, type);
+		break;
+	case HCLGE_ALGO_PARAM_HC3:
+		strncpy(type, "hc3", strlen("hc3") + 1);
+		hclge_devlink_hc3_param_get(devlink, ctx, type);
+		break;
+	case HCLGE_ALGO_PARAM_DIP:
+		strncpy(type, "dip", strlen("dip") + 1);
+		hclge_devlink_dip_param_get(devlink, ctx, type);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void
+hclge_algo_param_print_dcqcn(struct hclge_dev *hdev,
+			     const struct hclge_cfg_dcqcn_param *dcqcn_param)
+{
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+	int len = __DEVLINK_PARAM_MAX_STRING_VALUE;
+	int pos = 0;
+
+	pos += scnprintf(str + pos, len - pos, "type:  dcqcn\n");
+	pos += scnprintf(str + pos, len - pos, "AI:  %u\n", dcqcn_param->ai);
+	pos += scnprintf(str + pos, len - pos, "F:  %u\n", dcqcn_param->f);
+	pos += scnprintf(str + pos, len - pos, "TKP:  %u\n", dcqcn_param->tkp);
+	pos += scnprintf(str + pos, len - pos, "TMP:  %u\n", dcqcn_param->tmp);
+	pos += scnprintf(str + pos, len - pos, "ALP:  %u\n", dcqcn_param->alp);
+	pos += scnprintf(str + pos, len - pos, "MAX_SPEED:  %u\n",
+			 dcqcn_param->max_speed);
+	pos += scnprintf(str + pos, len - pos, "G:  %u\n", dcqcn_param->g);
+	pos += scnprintf(str + pos, len - pos, "AL:  %u\n", dcqcn_param->al);
+	pos += scnprintf(str + pos, len - pos, "CNP_TIME:  %u\n",
+			 dcqcn_param->cnp_time);
+	pos += scnprintf(str + pos, len - pos, "ALP_SHIFT:  %u\n",
+			 dcqcn_param->alp_shift);
+	dev_info(&hdev->pdev->dev, "%s", str);
+}
+
+static void
+hclge_algo_param_print_ldcp(struct hclge_dev *hdev,
+			    const struct hclge_cfg_ldcp_param *param)
+{
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+	int len = __DEVLINK_PARAM_MAX_STRING_VALUE;
+	int pos = 0;
+
+	pos += scnprintf(str + pos, len - pos, "type:  ldcp\n");
+	pos += scnprintf(str + pos, len - pos, "CWD_0:  %u\n", param->cwd0);
+	pos += scnprintf(str + pos, len - pos, "L_A:  %u\n", param->la);
+	pos += scnprintf(str + pos, len - pos, "L_Y:  %u\n", param->ly);
+	pos += scnprintf(str + pos, len - pos, "L_B:  %u\n", param->lb);
+	pos += scnprintf(str + pos, len - pos, "L_G:  %u\n", param->lg);
+	dev_info(&hdev->pdev->dev, "%s", str);
+}
+
+static void hclge_algo_param_print_hc3(struct hclge_dev *hdev,
+				       const struct hclge_cfg_hc3_param *param)
+{
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+	int len = __DEVLINK_PARAM_MAX_STRING_VALUE;
+	int pos = 0;
+
+	pos += scnprintf(str + pos, len - pos, "type:  hc3\n");
+	pos += scnprintf(str + pos, len - pos, "WIN:  %u\n", param->win);
+	pos += scnprintf(str + pos, len - pos, "HC_B:  %u\n", param->hcb);
+	pos += scnprintf(str + pos, len - pos, "MAX_QS:  %u\n", param->maxqs);
+	pos += scnprintf(str + pos, len - pos, "HC_ALP:  %u\n", param->hcalp);
+	pos += scnprintf(str + pos, len - pos, "HC_T:  %u\n", param->hct);
+	pos += scnprintf(str + pos, len - pos, "MAX_STG:  %u\n", param->maxstg);
+	pos += scnprintf(str + pos, len - pos, "GAM_SHIFT:  %u\n",
+			 param->gamshift);
+	dev_info(&hdev->pdev->dev, "%s", str);
+}
+
+static void hclge_algo_param_print_dip(struct hclge_dev *hdev,
+				       const struct hclge_cfg_dip_param *param)
+{
+	char str[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+	int len = __DEVLINK_PARAM_MAX_STRING_VALUE;
+	int pos = 0;
+
+	pos += scnprintf(str + pos, len - pos, "type:  dip\n");
+	pos += scnprintf(str + pos, len - pos, "AI:  %u\n", param->ai);
+	pos += scnprintf(str + pos, len - pos, "F:  %u\n", param->f);
+	pos += scnprintf(str + pos, len - pos, "TKP:  %u\n", param->tkp);
+	pos += scnprintf(str + pos, len - pos, "TMP:  %u\n", param->tmp);
+	pos += scnprintf(str + pos, len - pos, "ALP:  %u\n", param->alp);
+	pos += scnprintf(str + pos, len - pos, "MAX_SPEED:  %u\n",
+			 param->max_speed);
+	pos += scnprintf(str + pos, len - pos, "G:  %u\n", param->g);
+	pos += scnprintf(str + pos, len - pos, "AL:  %u\n", param->al);
+	pos += scnprintf(str + pos, len - pos, "CNP_TIME:  %u\n",
+			 param->cnp_time);
+	pos += scnprintf(str + pos, len - pos, "ALP_SHIFT:  %u\n",
+			 param->alp_shift);
+	dev_info(&hdev->pdev->dev, "%s", str);
+}
+
+enum HCLGE_ALGO_PARAM_SIZE_TYPE {
+	ALGO_SIZE_U8,
+	ALGO_SIZE_U16,
+	ALGO_SIZE_U32,
+};
+
+struct algo_param_item {
+	const char *name;
+	u64 max;
+	u64 value;
+	int offset;
+	enum HCLGE_ALGO_PARAM_SIZE_TYPE size_type;
+	const char *error_log;
+};
+
+struct algo_param_item dcqcn_items[] = {
+	{"ai@", 65535, 0, offsetof(struct hclge_cfg_dcqcn_param, ai),
+	 ALGO_SIZE_U16, "param ai of dcqcn overflow!\n"},
+	{"f@", 255, 0, offsetof(struct hclge_cfg_dcqcn_param, f),
+	 ALGO_SIZE_U8, "param f of dcqcn overflow!\n"},
+	{"tkp@", 15, 0, offsetof(struct hclge_cfg_dcqcn_param, tkp),
+	 ALGO_SIZE_U8, "param tkp of dcqcn overflow!\n"},
+	{"tmp@", 15, 0, offsetof(struct hclge_cfg_dcqcn_param, tmp),
+	 ALGO_SIZE_U16, "param tmp of dcqcn overflow!\n"},
+	{"alp@", 65535, 0, offsetof(struct hclge_cfg_dcqcn_param, alp),
+	 ALGO_SIZE_U16, "param alp of dcqcn overflow!\n"},
+	{"maxspeed@", UINT_MAX, 0, offsetof(struct hclge_cfg_dcqcn_param, max_speed),
+	 ALGO_SIZE_U32, "param maxspeed of dcqcn overflow!\n"},
+	{"g@", 15, 0, offsetof(struct hclge_cfg_dcqcn_param, g),
+	 ALGO_SIZE_U8, "param g of dcqcn overflow!\n"},
+	{"al@", 255, 0, offsetof(struct hclge_cfg_dcqcn_param, al),
+	 ALGO_SIZE_U8, "param al of dcqcn overflow!\n"},
+	{"cnptime@", 255, 0, offsetof(struct hclge_cfg_dcqcn_param, cnp_time),
+	 ALGO_SIZE_U8, "param cnptime of dcqcn overflow!\n"},
+	{"alpshift@", 15, 0, offsetof(struct hclge_cfg_dcqcn_param, alp_shift),
+	 ALGO_SIZE_U8, "param alpshift of dcqcn overflow!\n"},
+};
+
+struct algo_param_item ldcp_items[] = {
+	{"cwd0@", UINT_MAX, 0, offsetof(struct hclge_cfg_ldcp_param, cwd0),
+	 ALGO_SIZE_U32, "param cwd0 of ldcp overflow!\n"},
+	{"la@", 255, 0, offsetof(struct hclge_cfg_ldcp_param, la),
+	 ALGO_SIZE_U8, "param la of ldcp overflow!\n"},
+	{"ly@", 255, 0, offsetof(struct hclge_cfg_ldcp_param, ly),
+	 ALGO_SIZE_U8, "param ly of ldcp overflow!\n"},
+	{"lb@", 255, 0, offsetof(struct hclge_cfg_ldcp_param, lb),
+	 ALGO_SIZE_U8, "param lb of ldcp overflow!\n"},
+	{"lg@", 255, 0, offsetof(struct hclge_cfg_ldcp_param, lg),
+	 ALGO_SIZE_U8, "param lg of ldcp overflow!\n"},
+};
+
+struct algo_param_item hc3_items[] = {
+	{"win@", UINT_MAX, 0, offsetof(struct hclge_cfg_hc3_param, win),
+	 ALGO_SIZE_U32, "param win of hc3 overflow!\n"},
+	{"hcb@", UINT_MAX, 0, offsetof(struct hclge_cfg_hc3_param, hcb),
+	 ALGO_SIZE_U32, "param hcb of hc3 overflow!\n"},
+	{"maxqs@", 255, 0, offsetof(struct hclge_cfg_hc3_param, maxqs),
+	 ALGO_SIZE_U8, "param maxqs of hc3 overflow!\n"},
+	{"hcalp@", 255, 0, offsetof(struct hclge_cfg_hc3_param, hcalp),
+	 ALGO_SIZE_U8, "param hcalp of hc3 overflow!\n"},
+	{"hct@", 255, 0, offsetof(struct hclge_cfg_hc3_param, hct),
+	 ALGO_SIZE_U8, "param hct of hc3 overflow!\n"},
+	{"maxstg@", 255, 0, offsetof(struct hclge_cfg_hc3_param, maxstg),
+	 ALGO_SIZE_U8, "param maxstg of hc3 overflow!\n"},
+	{"gamshift@", 15, 0, offsetof(struct hclge_cfg_hc3_param, gamshift),
+	 ALGO_SIZE_U8, "param gamshift of hc3 overflow!\n"},
+};
+
+struct algo_param_item dip_items[] = {
+	{"ai@", 65535, 0, offsetof(struct hclge_cfg_dip_param, ai),
+	 ALGO_SIZE_U16, "param ai of dip overflow!\n"},
+	{"f@", 255, 0, offsetof(struct hclge_cfg_dip_param, f),
+	 ALGO_SIZE_U8, "param f of dip overflow!\n"},
+	{"tkp@", 15, 0, offsetof(struct hclge_cfg_dip_param, tkp),
+	 ALGO_SIZE_U8, "param tkp of dip overflow!\n"},
+	{"tmp@", 15, 0, offsetof(struct hclge_cfg_dip_param, tmp),
+	 ALGO_SIZE_U16, "param tmp of dip overflow!\n"},
+	{"alp@", 65535, 0, offsetof(struct hclge_cfg_dip_param, alp),
+	 ALGO_SIZE_U16, "param alp of dip overflow!\n"},
+	{"maxspeed@", UINT_MAX, 0, offsetof(struct hclge_cfg_dip_param, max_speed),
+	 ALGO_SIZE_U32, "param maxspeed of dip overflow!\n"},
+	{"g@", 15, 0, offsetof(struct hclge_cfg_dip_param, g),
+	 ALGO_SIZE_U8, "param g of dip overflow!\n"},
+	{"al@", 255, 0, offsetof(struct hclge_cfg_dip_param, al),
+	 ALGO_SIZE_U8, "param al of dip overflow!\n"},
+	{"cnptime@", 255, 0, offsetof(struct hclge_cfg_dip_param, cnp_time),
+	 ALGO_SIZE_U8, "param cnptime of dip overflow!\n"},
+	{"alpshift@", 15, 0, offsetof(struct hclge_cfg_dip_param, alp_shift),
+	 ALGO_SIZE_U8, "param alpshift of dip overflow!\n"},
+};
+
+struct algo_param_item *algo_items[] = {
+	[HCLGE_ALGO_PARAM_DCQCN] = dcqcn_items,
+	[HCLGE_ALGO_PARAM_LDCP] = ldcp_items,
+	[HCLGE_ALGO_PARAM_HC3] = hc3_items,
+	[HCLGE_ALGO_PARAM_DIP] = dip_items,
+};
+
+const u32 algo_items_size[] = {
+	[HCLGE_ALGO_PARAM_DCQCN] = ARRAY_SIZE(dcqcn_items),
+	[HCLGE_ALGO_PARAM_LDCP] = ARRAY_SIZE(ldcp_items),
+	[HCLGE_ALGO_PARAM_HC3] = ARRAY_SIZE(hc3_items),
+	[HCLGE_ALGO_PARAM_DIP] = ARRAY_SIZE(dip_items),
+};
+
+const u64 algo_items_param_offset[] = {
+	[HCLGE_ALGO_PARAM_DCQCN] = offsetof(struct hclge_cfg_algo_param, dcqcn_param),
+	[HCLGE_ALGO_PARAM_LDCP] = offsetof(struct hclge_cfg_algo_param, ldcp_param),
+	[HCLGE_ALGO_PARAM_HC3] = offsetof(struct hclge_cfg_algo_param, hc3_param),
+	[HCLGE_ALGO_PARAM_DIP] = offsetof(struct hclge_cfg_algo_param, dip_param),
+};
+
+static int hclge_devlink_find_item(const struct algo_param_item *items,
+				   u32 size, const char *str)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (!strncmp(str, items[i].name, strlen(items[i].name)))
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int hclge_devlink_get_algo_param_value(const char *str, u64 *param_value)
+{
+	char *value, *value_tmp, *tmp;
+	int ret = 0;
+	int i;
+
+	value = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
+			GFP_KERNEL);
+	if (!value)
+		return -ENOMEM;
+
+	strncpy(value, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
+	value_tmp = value;
+
+	tmp = strsep(&value, "@");
+
+	for (i = 0; i < strlen(value); i++) {
+		if (!(value[i] >= '0' && value[i] <= '9')) {
+			kfree(value_tmp);
+			return -EINVAL;
+		}
+	}
+
+	ret = kstrtou64(value, 0, param_value);
+
+	kfree(value_tmp);
+	return ret;
+}
+
+static int hclge_devlink_set_algo_param_dcqcn(struct hclge_dev *hdev,
+					      u8 *param_addr)
+{
+	struct hclge_cfg_dcqcn_param *dcqcn_param =
+				(struct hclge_cfg_dcqcn_param *)param_addr;
+	struct hclge_dcqcn_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_DCQCN,
+					false);
+	req = (struct hclge_dcqcn_param_cfg_cmd *)desc.data;
+	req->ai = cpu_to_le16(dcqcn_param->ai);
+	req->f = dcqcn_param->f;
+	req->tkp = dcqcn_param->tkp;
+	req->tmp = cpu_to_le16(dcqcn_param->tmp);
+	req->alp = cpu_to_le16(dcqcn_param->alp);
+	req->max_speed = cpu_to_le32(dcqcn_param->max_speed);
+	req->g = dcqcn_param->g;
+	req->al = dcqcn_param->al;
+	req->cnp_time = dcqcn_param->cnp_time;
+	req->alp_shift = dcqcn_param->alp_shift;
+
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret)
+		dev_err(&hdev->pdev->dev,
+			"set dcqcn param fail, ret = %d\n", ret);
+	return ret;
+}
+
+static int hclge_devlink_set_algo_param_ldcp(struct hclge_dev *hdev,
+					     u8 *param_addr)
+{
+	struct hclge_cfg_ldcp_param *ldcp_param =
+				(struct hclge_cfg_ldcp_param *)param_addr;
+	struct hclge_ldcp_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_LDCP,
+					false);
+	req = (struct hclge_ldcp_param_cfg_cmd *)desc.data;
+	req->cwd0 = cpu_to_le32(ldcp_param->cwd0);
+	req->la = ldcp_param->la;
+	req->ly = ldcp_param->ly;
+	req->lb = ldcp_param->lb;
+	req->lg = ldcp_param->lg;
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret)
+		dev_err(&hdev->pdev->dev,
+			"set ldcp param fail, ret = %d\n", ret);
+	return ret;
+}
+
+static int hclge_devlink_set_algo_param_hc3(struct hclge_dev *hdev,
+					    u8 *param_addr)
+{
+	struct hclge_cfg_hc3_param *hc3_param =
+				(struct hclge_cfg_hc3_param *)param_addr;
+	struct hclge_hc3_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_HC3, false);
+	req = (struct hclge_hc3_param_cfg_cmd *)desc.data;
+	req->win = cpu_to_le32(hc3_param->win);
+	req->hcb = cpu_to_le32(hc3_param->hcb);
+	req->maxqs = hc3_param->maxqs;
+	req->hcalp = hc3_param->hcalp;
+	req->hct = hc3_param->hct;
+	req->maxstg = hc3_param->maxstg;
+	req->gamshift = hc3_param->gamshift;
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret)
+		dev_err(&hdev->pdev->dev,
+			"set hc3 param fail, ret = %d\n", ret);
+	return ret;
+}
+
+static int hclge_devlink_set_algo_param_dip(struct hclge_dev *hdev,
+					    u8 *param_addr)
+{
+	struct hclge_cfg_dip_param *dip_param =
+				(struct hclge_cfg_dip_param *)param_addr;
+	struct hclge_dip_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_comm_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_DIP, false);
+	req = (struct hclge_dip_param_cfg_cmd *)desc.data;
+	req->ai = cpu_to_le16(dip_param->ai);
+	req->f = dip_param->f;
+	req->tkp = dip_param->tkp;
+	req->tmp = cpu_to_le16(dip_param->tmp);
+	req->alp = cpu_to_le16(dip_param->alp);
+	req->max_speed = cpu_to_le32(dip_param->max_speed);
+	req->g = dip_param->g;
+	req->al = dip_param->al;
+	req->cnp_time = dip_param->cnp_time;
+	req->alp_shift = dip_param->alp_shift;
+
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret)
+		dev_err(&hdev->pdev->dev,
+			"set dip param fail, ret = %d\n", ret);
+	return ret;
+}
+
+void hclge_restore_algo_param(struct hclge_dev *hdev)
+{
+	int ret;
+
+	if (hdev->ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2)
+		return;
+
+	ret = hclge_devlink_set_algo_param_dcqcn(hdev, (u8 *)&hdev->algo_param.dcqcn_param);
+	if (ret)
+		return;
+
+	ret = hclge_devlink_set_algo_param_ldcp(hdev, (u8 *)&hdev->algo_param.ldcp_param);
+	if (ret)
+		return;
+
+	ret = hclge_devlink_set_algo_param_hc3(hdev, (u8 *)&hdev->algo_param.hc3_param);
+	if (ret)
+		return;
+
+	ret = hclge_devlink_set_algo_param_dip(hdev, (u8 *)&hdev->algo_param.dip_param);
+}
+
+static int hclge_devlink_set_algo_param(struct hclge_dev *hdev, u8 *param_addr,
+					enum HCLGE_ALGO_PARAM_TYPE type)
+{
+	int ret;
+
+	switch (type) {
+	case HCLGE_ALGO_PARAM_DCQCN:
+		ret = hclge_devlink_set_algo_param_dcqcn(hdev, param_addr);
+		if (ret)
+			return ret;
+
+		hdev->algo_param.dcqcn_param = *(struct hclge_cfg_dcqcn_param *)param_addr;
+		hclge_algo_param_print_dcqcn(hdev, &hdev->algo_param.dcqcn_param);
+		break;
+	case HCLGE_ALGO_PARAM_LDCP:
+		ret = hclge_devlink_set_algo_param_ldcp(hdev, param_addr);
+		if (ret)
+			return ret;
+
+		hdev->algo_param.ldcp_param = *(struct hclge_cfg_ldcp_param *)param_addr;
+		hclge_algo_param_print_ldcp(hdev, &hdev->algo_param.ldcp_param);
+		break;
+	case HCLGE_ALGO_PARAM_HC3:
+		ret = hclge_devlink_set_algo_param_hc3(hdev, param_addr);
+		if (ret)
+			return ret;
+
+		hdev->algo_param.hc3_param = *(struct hclge_cfg_hc3_param *)param_addr;
+		hclge_algo_param_print_hc3(hdev, &hdev->algo_param.hc3_param);
+		break;
+	case HCLGE_ALGO_PARAM_DIP:
+		ret = hclge_devlink_set_algo_param_dip(hdev, param_addr);
+		if (ret)
+			return ret;
+
+		hdev->algo_param.dip_param = *(struct hclge_cfg_dip_param *)param_addr;
+		hclge_algo_param_print_dip(hdev, &hdev->algo_param.dip_param);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+hclge_devlink_algo_param_set_value(struct hclge_dev *hdev,
+				   enum HCLGE_ALGO_PARAM_TYPE type,
+				   struct devlink_param_gset_ctx *ctx)
+{
+	struct hclge_cfg_algo_param algo_param = hdev->algo_param;
+	char *tmp[HCLGE_DEVLINK_MAX_ALGO_PARAM_NUM] = {0};
+	struct algo_param_item *items = algo_items[type];
+	u64 algo_offset = algo_items_param_offset[type];
+	u8 *param_addr = (u8 *)&algo_param + algo_offset;
+	u32 size = algo_items_size[type];
+	char *str, *str_tmp;
+	u8 *item_addr;
+	int ret = 0;
+	int i = 0;
+	int y, k;
+
+	str = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
+		      GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+
+	strncpy(str, ctx->val.vstr, __DEVLINK_PARAM_MAX_STRING_VALUE);
+	str_tmp = str;
+	dev_info(&hdev->pdev->dev, "devlink algo param is setting: %s\n", str);
+	do {
+		tmp[i++] = strsep(&str, "_");
+	} while (i < HCLGE_DEVLINK_MAX_ALGO_PARAM_NUM && tmp[i - 1] && str);
+
+	for (y = 1; y < i; y++) {
+		/* k has been checked in validate function */
+		k = hclge_devlink_find_item(items, size, tmp[y]);
+		ret = hclge_devlink_get_algo_param_value(tmp[y],
+							 &items[k].value);
+		if (ret)
+			break;
+
+		switch (items[k].size_type) {
+		case ALGO_SIZE_U8:
+			item_addr = param_addr + items[k].offset;
+			*item_addr = (u8)items[k].value;
+			break;
+		case ALGO_SIZE_U16:
+			item_addr = param_addr + items[k].offset;
+			*(u16 *)item_addr = (u16)items[k].value;
+			break;
+		case ALGO_SIZE_U32:
+			item_addr = param_addr + items[k].offset;
+			*(u32 *)item_addr = (u32)items[k].value;
+			break;
+		default:
+			break;
+		}
+	}
+
+	ret = hclge_devlink_set_algo_param(hdev, param_addr, type);
+
+	kfree(str_tmp);
+	return ret;
+}
+
+static int hclge_devlink_algo_param_set(struct devlink *devlink, u32 id,
+					struct devlink_param_gset_ctx *ctx)
+{
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	char tmp_a[HCLGE_DEVLINK_MAX_ALGO_TYPE_LEN] = {0};
+	char type[HCLGE_DEVLINK_MAX_ALGO_TYPE_LEN] = {0};
+	struct hclge_dev *hdev = priv->hdev;
+	char *value, *value_tmp, *tmp;
+	int cnt = 0;
+	int ret;
+
+	value = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
+			GFP_KERNEL);
+	if (!value)
+		return -ENOMEM;
+
+	strncpy(value, ctx->val.vstr, __DEVLINK_PARAM_MAX_STRING_VALUE);
+	value_tmp = value;
+	tmp = strsep(&value, "_");
+	strncpy(tmp_a, tmp, strlen(tmp) + 1);
+	cnt = sscanf(tmp_a, "type@%s", type);
+
+	if (!strcmp(type, "dcqcn")) {
+		hdev->algo_param_type = HCLGE_ALGO_PARAM_DCQCN;
+	} else if (!strcmp(type, "ldcp")) {
+		hdev->algo_param_type = HCLGE_ALGO_PARAM_LDCP;
+	} else if (!strcmp(type, "hc3")) {
+		hdev->algo_param_type = HCLGE_ALGO_PARAM_HC3;
+	} else if (!strcmp(type, "dip")) {
+		hdev->algo_param_type = HCLGE_ALGO_PARAM_DIP;
+	} else {
+		dev_err(&hdev->pdev->dev, "unsupported algo type!\n");
+		kfree(value_tmp);
+		return -EINVAL;
+	}
+
+	ret = hclge_devlink_algo_param_set_value(hdev, hdev->algo_param_type,
+						 ctx);
+
+	kfree(value_tmp);
+	return ret;
+}
+
+static int hclge_devlink_is_algo_param_valid(char *str, u32 max)
+{
+	char *value, *value_tmp, *tmp;
+	int ret, i;
+	u64 tmp_u;
+
+	value = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
+			GFP_KERNEL);
+	if (!value)
+		return -ENOMEM;
+
+	strncpy(value, str, __DEVLINK_PARAM_MAX_STRING_VALUE);
+	value_tmp = value;
+
+	tmp = strsep(&value, "@");
+
+	for (i = 0; i < strlen(value); i++) {
+		if (!(value[i] >= '0' && value[i] <= '9')) {
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	ret = kstrtou64(value, 0, &tmp_u);
+	if (ret)
+		goto out;
+
+	if (tmp_u > max)
+		ret = -EINVAL;
+
+out:
+	kfree(value_tmp);
+	return ret;
+}
+
+static int hclge_devlink_algo_param_check(struct hclge_dev *hdev,
+					  union devlink_param_value val,
+					  enum HCLGE_ALGO_PARAM_TYPE type)
+{
+	const struct algo_param_item *items = algo_items[type];
+	char *tmp[HCLGE_DEVLINK_MAX_ALGO_PARAM_NUM] = {0};
+	u32 size = algo_items_size[type];
+	char *str, *str_tmp;
+	int ret = 0;
+	int i = 0;
+	int y, k;
+
+	str = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
+		      GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+
+	strncpy(str, val.vstr, __DEVLINK_PARAM_MAX_STRING_VALUE);
+	str_tmp = str;
+
+	do {
+		tmp[i++] = strsep(&str, "_");
+	} while (i < HCLGE_DEVLINK_MAX_ALGO_PARAM_NUM && tmp[i - 1] && str);
+
+	for (y = 1; y < i; y++) {
+		k = hclge_devlink_find_item(items, size, tmp[y]);
+		if (k < 0) {
+			dev_err(&hdev->pdev->dev, "unsupported algo param!\n");
+			ret = k;
+			break;
+		}
+
+		ret = hclge_devlink_is_algo_param_valid(tmp[y], items[k].max);
+		if (ret) {
+			dev_err(&hdev->pdev->dev, "%s", items[k].error_log);
+			break;
+		}
+	}
+
+	kfree(str_tmp);
+	return ret;
+}
+
+static int
+hclge_devlink_algo_param_validate(struct devlink *devlink, u32 id,
+				  union devlink_param_value val,
+				  struct netlink_ext_ack *extack)
+{
+	struct hclge_devlink_priv *priv = devlink_priv(devlink);
+	char tmp_a[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+	char type[__DEVLINK_PARAM_MAX_STRING_VALUE] = {0};
+	struct hclge_dev *hdev = priv->hdev;
+	char *str, *str_tmp, *tmp;
+	int ret = 0;
+
+	str = kmalloc(sizeof(char) * __DEVLINK_PARAM_MAX_STRING_VALUE,
+		      GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+
+	strncpy(str, val.vstr, __DEVLINK_PARAM_MAX_STRING_VALUE);
+	str_tmp = str;
+	tmp = strsep(&str, "_");
+	strncpy(tmp_a, tmp, strlen(tmp) + 1);
+	ret = sscanf(tmp_a, "type@%s", type);
+	if (ret < 0) {
+		NL_SET_ERR_MSG_MOD(extack, "invalid algo type!");
+		kfree(str_tmp);
+		return ret;
+	}
+
+	if (!strcmp(type, "dcqcn")) {
+		ret = hclge_devlink_algo_param_check(hdev, val, HCLGE_ALGO_PARAM_DCQCN);
+	} else if (!strcmp(type, "ldcp")) {
+		ret = hclge_devlink_algo_param_check(hdev, val, HCLGE_ALGO_PARAM_LDCP);
+	} else if (!strcmp(type, "hc3")) {
+		ret = hclge_devlink_algo_param_check(hdev, val, HCLGE_ALGO_PARAM_HC3);
+	} else if (!strcmp(type, "dip")) {
+		ret = hclge_devlink_algo_param_check(hdev, val, HCLGE_ALGO_PARAM_DIP);
+	} else {
+		ret = -EINVAL;
+		NL_SET_ERR_MSG_MOD(extack, "unsupported algo type!");
+	}
+
+	kfree(str_tmp);
+	return ret;
+}
+
 static const struct devlink_ops hclge_devlink_ops = {
 	.info_get = hclge_devlink_info_get,
 	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
@@ -104,11 +852,31 @@  static const struct devlink_ops hclge_devlink_ops = {
 	.reload_up = hclge_devlink_reload_up,
 };
 
+static const struct devlink_param hclge_devlink_params[] = {
+	DEVLINK_PARAM_DRIVER(HCLGE_DEVLINK_PARAM_ID_ALGO_PARAM,
+			     "algo_param", DEVLINK_PARAM_TYPE_STRING,
+			     BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+			     hclge_devlink_algo_param_get,
+			     hclge_devlink_algo_param_set,
+			     hclge_devlink_algo_param_validate),
+};
+
+static void hclge_devlink_set_params_init_values(struct devlink *devlink)
+{
+	union devlink_param_value value;
+
+	strncpy(value.vstr, "type@dcqcn", strlen("type@dcqcn") + 1);
+	devlink_param_driverinit_value_set(devlink,
+					   HCLGE_DEVLINK_PARAM_ID_ALGO_PARAM,
+					   value);
+}
+
 int hclge_devlink_init(struct hclge_dev *hdev)
 {
 	struct pci_dev *pdev = hdev->pdev;
 	struct hclge_devlink_priv *priv;
 	struct devlink *devlink;
+	int ret = 0;
 
 	devlink = devlink_alloc(&hclge_devlink_ops,
 				sizeof(struct hclge_devlink_priv), &pdev->dev);
@@ -119,8 +887,23 @@  int hclge_devlink_init(struct hclge_dev *hdev)
 	priv->hdev = hdev;
 	hdev->devlink = devlink;
 
+	if (pdev->revision > HNAE3_DEVICE_VERSION_V2) {
+		ret = devlink_params_register(devlink, hclge_devlink_params,
+					      ARRAY_SIZE(hclge_devlink_params));
+		if (ret) {
+			dev_err(&pdev->dev,
+				"failed to register devlink params, ret = %d\n",
+				ret);
+			devlink_free(devlink);
+			return ret;
+		}
+
+		hclge_devlink_set_params_init_values(devlink);
+	}
+
 	devlink_set_features(devlink, DEVLINK_F_RELOAD);
 	devlink_register(devlink);
+
 	return 0;
 }
 
@@ -130,5 +913,10 @@  void hclge_devlink_uninit(struct hclge_dev *hdev)
 
 	devlink_unregister(devlink);
 
+	if (hdev->pdev->revision > HNAE3_DEVICE_VERSION_V2) {
+		devlink_params_unregister(devlink, hclge_devlink_params,
+					  ARRAY_SIZE(hclge_devlink_params));
+	}
+
 	devlink_free(devlink);
 }
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h
index 918be04507a5..93616080504e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_devlink.h
@@ -10,6 +10,12 @@  struct hclge_devlink_priv {
 	struct hclge_dev *hdev;
 };
 
+enum hclge_devlink_param_id {
+	HCLGE_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
+	HCLGE_DEVLINK_PARAM_ID_ALGO_PARAM,
+};
+
 int hclge_devlink_init(struct hclge_dev *hdev);
 void hclge_devlink_uninit(struct hclge_dev *hdev);
+void hclge_restore_algo_param(struct hclge_dev *hdev);
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 6962a9d69cf8..47045dcc947d 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -10244,6 +10244,7 @@  static void hclge_restore_hw_table(struct hclge_dev *hdev)
 	hclge_restore_vport_vlan_table(vport);
 	set_bit(HCLGE_STATE_FD_USER_DEF_CHANGED, &hdev->state);
 	hclge_restore_fd_entries(handle);
+	hclge_restore_algo_param(hdev);
 }
 
 int hclge_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable)
@@ -11488,6 +11489,125 @@  static int hclge_clear_hw_resource(struct hclge_dev *hdev)
 	return 0;
 }
 
+static void hclge_query_dcqcn_param(struct hclge_dev *hdev)
+{
+	struct hclge_cfg_dcqcn_param *dcqcn_param;
+	struct hclge_dcqcn_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_DCQCN, true);
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to query dcqcn param, ret = %d\n", ret);
+		return;
+	}
+
+	req = (struct hclge_dcqcn_param_cfg_cmd *)desc.data;
+	dcqcn_param = &hdev->algo_param.dcqcn_param;
+	dcqcn_param->ai = __le16_to_cpu(req->ai);
+	dcqcn_param->f = req->f;
+	dcqcn_param->tkp = req->tkp;
+	dcqcn_param->tmp = __le16_to_cpu(req->tmp);
+	dcqcn_param->alp = __le16_to_cpu(req->alp);
+	dcqcn_param->max_speed = __le32_to_cpu(req->max_speed);
+	dcqcn_param->g = req->g;
+	dcqcn_param->al = req->al;
+	dcqcn_param->cnp_time = req->cnp_time;
+	dcqcn_param->alp_shift = req->alp_shift;
+}
+
+static void hclge_query_ldcp_param(struct hclge_dev *hdev)
+{
+	struct hclge_cfg_ldcp_param *ldcp_param;
+	struct hclge_ldcp_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_LDCP, true);
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to query ldcp param, ret = %d\n", ret);
+		return;
+	}
+
+	req = (struct hclge_ldcp_param_cfg_cmd *)desc.data;
+	ldcp_param = &hdev->algo_param.ldcp_param;
+	ldcp_param->cwd0 =  __le32_to_cpu(req->cwd0);
+	ldcp_param->la = req->la;
+	ldcp_param->ly = req->ly;
+	ldcp_param->lb = req->lb;
+	ldcp_param->lg = req->lg;
+}
+
+static void hclge_query_hc3_param(struct hclge_dev *hdev)
+{
+	struct hclge_cfg_hc3_param *hc3_param;
+	struct hclge_hc3_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_HC3, true);
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to query hc3 param, ret = %d\n", ret);
+		return;
+	}
+
+	req = (struct hclge_hc3_param_cfg_cmd *)desc.data;
+	hc3_param = &hdev->algo_param.hc3_param;
+	hc3_param->win = __le32_to_cpu(req->win);
+	hc3_param->hcb = __le32_to_cpu(req->hcb);
+	hc3_param->maxqs = req->maxqs;
+	hc3_param->hcalp = req->hcalp;
+	hc3_param->hct = req->hct;
+	hc3_param->maxstg = req->maxstg;
+	hc3_param->gamshift = req->gamshift;
+}
+
+static void hclge_query_dip_param(struct hclge_dev *hdev)
+{
+	struct hclge_cfg_dip_param *dip_param;
+	struct hclge_dip_param_cfg_cmd *req;
+	struct hclge_desc desc;
+	int ret;
+
+	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_ALGO_PARAM_DIP, true);
+	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+	if (ret) {
+		dev_err(&hdev->pdev->dev,
+			"failed to query dip param, ret = %d\n", ret);
+		return;
+	}
+
+	req = (struct hclge_dip_param_cfg_cmd *)desc.data;
+	dip_param = &hdev->algo_param.dip_param;
+	dip_param->ai = __le16_to_cpu(req->ai);
+	dip_param->f = req->f;
+	dip_param->tkp = req->tkp;
+	dip_param->tmp = __le16_to_cpu(req->tmp);
+	dip_param->alp = __le16_to_cpu(req->alp);
+	dip_param->max_speed = __le32_to_cpu(req->max_speed);
+	dip_param->g = req->g;
+	dip_param->al = req->al;
+	dip_param->cnp_time = req->cnp_time;
+	dip_param->alp_shift = req->alp_shift;
+}
+
+static void hclge_query_algo_param(struct hclge_dev *hdev)
+{
+	if (hdev->ae_dev->dev_version <= HNAE3_DEVICE_VERSION_V2)
+		return;
+
+	hclge_query_dcqcn_param(hdev);
+	hclge_query_ldcp_param(hdev);
+	hclge_query_hc3_param(hdev);
+	hclge_query_dip_param(hdev);
+}
+
 static void hclge_init_rxd_adv_layout(struct hclge_dev *hdev)
 {
 	if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev))
@@ -11690,6 +11810,8 @@  static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
 
 	hclge_init_rxd_adv_layout(hdev);
 
+	hclge_query_algo_param(hdev);
+
 	/* Enable MISC vector(vector0) */
 	hclge_enable_vector(&hdev->misc_vector, true);
 
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index 495b639b0dc2..69f1b9a363fc 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -811,6 +811,65 @@  struct hclge_vf_vlan_cfg {
 
 #pragma pack()
 
+struct hclge_cfg_dcqcn_param {
+	u16 ai;
+	u8 f;
+	u8 tkp;
+	u16 tmp;
+	u16 alp;
+	u32 max_speed;
+	u8 g;
+	u8 al;
+	u8 cnp_time;
+	u8 alp_shift;
+};
+
+struct hclge_cfg_ldcp_param {
+	u32 cwd0;
+	u8 la;
+	u8 ly;
+	u8 lb;
+	u8 lg;
+};
+
+struct hclge_cfg_hc3_param {
+	u32 win;
+	u32 hcb;
+	u8 maxqs;
+	u8 hcalp;
+	u8 hct;
+	u8 maxstg;
+	u8 gamshift;
+};
+
+struct hclge_cfg_dip_param {
+	u16 ai;
+	u8 f;
+	u8 tkp;
+	u16 tmp;
+	u16 alp;
+	u32 max_speed;
+	u8 g;
+	u8 al;
+	u8 cnp_time;
+	u8 alp_shift;
+};
+
+struct hclge_cfg_algo_param {
+	struct hclge_cfg_dcqcn_param dcqcn_param;
+	struct hclge_cfg_ldcp_param ldcp_param;
+	struct hclge_cfg_hc3_param hc3_param;
+	struct hclge_cfg_dip_param dip_param;
+};
+
+enum HCLGE_ALGO_PARAM_TYPE {
+	HCLGE_ALGO_PARAM_DCQCN,
+	HCLGE_ALGO_PARAM_LDCP,
+	HCLGE_ALGO_PARAM_HC3,
+	HCLGE_ALGO_PARAM_DIP,
+	HCLGE_ALGO_PARAM_UNSUPPORT
+};
+
 /* For each bit of TCAM entry, it uses a pair of 'x' and
  * 'y' to indicate which value to match, like below:
  * ----------------------------------
@@ -869,6 +928,8 @@  struct hclge_dev {
 	u16 vf_rss_size_max;		/* HW defined VF max RSS task queue */
 	u16 pf_rss_size_max;		/* HW defined PF max RSS task queue */
 	u32 tx_spare_buf_size;		/* HW defined TX spare buffer size */
+	struct hclge_cfg_algo_param algo_param;
+	enum HCLGE_ALGO_PARAM_TYPE algo_param_type;
 
 	u16 fdir_pf_filter_count; /* Num of guaranteed filters for this PF */
 	u16 num_alloc_vport;		/* Num vports this driver supports */