xref: /linux/drivers/net/ethernet/mellanox/mlx5/core/lib/nv_param.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3 
4 #include "nv_param.h"
5 #include "mlx5_core.h"
6 
7 enum {
8 	MLX5_CLASS_0_CTRL_ID_NV_GLOBAL_PCI_CONF               = 0x80,
9 	MLX5_CLASS_0_CTRL_ID_NV_GLOBAL_PCI_CAP                = 0x81,
10 	MLX5_CLASS_0_CTRL_ID_NV_SW_OFFLOAD_CONFIG             = 0x10a,
11 	MLX5_CLASS_0_CTRL_ID_NV_SW_OFFLOAD_CAP                = 0x10b,
12 	MLX5_CLASS_0_CTRL_ID_NV_SW_ACCELERATE_CONF            = 0x11d,
13 
14 	MLX5_CLASS_3_CTRL_ID_NV_PF_PCI_CONF                   = 0x80,
15 };
16 
17 struct mlx5_ifc_configuration_item_type_class_global_bits {
18 	u8         type_class[0x8];
19 	u8         parameter_index[0x18];
20 };
21 
22 struct mlx5_ifc_configuration_item_type_class_per_host_pf_bits {
23 	u8         type_class[0x8];
24 	u8         pf_index[0x6];
25 	u8         pci_bus_index[0x8];
26 	u8         parameter_index[0xa];
27 };
28 
29 union mlx5_ifc_config_item_type_auto_bits {
30 	struct mlx5_ifc_configuration_item_type_class_global_bits
31 				configuration_item_type_class_global;
32 	struct mlx5_ifc_configuration_item_type_class_per_host_pf_bits
33 				configuration_item_type_class_per_host_pf;
34 	u8 reserved_at_0[0x20];
35 };
36 
37 enum {
38 	MLX5_ACCESS_MODE_NEXT = 0,
39 	MLX5_ACCESS_MODE_CURRENT,
40 	MLX5_ACCESS_MODE_DEFAULT,
41 };
42 
43 struct mlx5_ifc_config_item_bits {
44 	u8         valid[0x2];
45 	u8         priority[0x2];
46 	u8         header_type[0x2];
47 	u8         ovr_en[0x1];
48 	u8         rd_en[0x1];
49 	u8         access_mode[0x2];
50 	u8         reserved_at_a[0x1];
51 	u8         writer_id[0x5];
52 	u8         version[0x4];
53 	u8         reserved_at_14[0x2];
54 	u8         host_id_valid[0x1];
55 	u8         length[0x9];
56 
57 	union mlx5_ifc_config_item_type_auto_bits type;
58 
59 	u8         reserved_at_40[0x10];
60 	u8         crc16[0x10];
61 };
62 
63 struct mlx5_ifc_mnvda_reg_bits {
64 	struct mlx5_ifc_config_item_bits configuration_item_header;
65 
66 	u8         configuration_item_data[64][0x20];
67 };
68 
69 struct mlx5_ifc_nv_global_pci_conf_bits {
70 	u8         sriov_valid[0x1];
71 	u8         reserved_at_1[0xa];
72 	u8         per_pf_num_sf[0x1];
73 	u8         reserved_at_c[0x5];
74 	u8         per_pf_total_vf[0x1];
75 	u8         reserved_at_12[0xe];
76 
77 	u8         sriov_en[0x1];
78 	u8         reserved_at_21[0xf];
79 	u8         total_vfs[0x10];
80 
81 	u8         reserved_at_40[0x20];
82 };
83 
84 struct mlx5_ifc_nv_global_pci_cap_bits {
85 	u8         max_vfs_per_pf_valid[0x1];
86 	u8         reserved_at_1[0x13];
87 	u8         per_pf_total_vf_supported[0x1];
88 	u8         reserved_at_15[0xb];
89 
90 	u8         sriov_support[0x1];
91 	u8         reserved_at_21[0xf];
92 	u8         max_vfs_per_pf[0x10];
93 
94 	u8         reserved_at_40[0x60];
95 };
96 
97 struct mlx5_ifc_nv_pf_pci_conf_bits {
98 	u8         log_sf_bar_size[0x8];
99 	u8         pf_total_sf_en[0x1];
100 	u8         pf_total_vf_en[0x1];
101 	u8         reserved_at_a[0x6];
102 	u8         total_sf[0x10];
103 
104 	u8         reserved_at_20[0x20];
105 
106 	u8         reserved_at_40[0x10];
107 	u8         total_vf[0x10];
108 
109 	u8         reserved_at_60[0x20];
110 };
111 
112 struct mlx5_ifc_nv_sw_offload_conf_bits {
113 	u8         ip_over_vxlan_port[0x10];
114 	u8         tunnel_ecn_copy_offload_disable[0x1];
115 	u8         pci_atomic_mode[0x3];
116 	u8         sr_enable[0x1];
117 	u8         ptp_cyc2realtime[0x1];
118 	u8         vector_calc_disable[0x1];
119 	u8         uctx_en[0x1];
120 	u8         prio_tag_required_en[0x1];
121 	u8         esw_fdb_ipv4_ttl_modify_enable[0x1];
122 	u8         mkey_by_name[0x1];
123 	u8         ip_over_vxlan_en[0x1];
124 	u8         one_qp_per_recovery[0x1];
125 	u8         cqe_compression[0x3];
126 	u8         tunnel_udp_entropy_proto_disable[0x1];
127 	u8         reserved_at_21[0x1];
128 	u8         ar_enable[0x1];
129 	u8         log_max_outstanding_wqe[0x5];
130 	u8         vf_migration[0x2];
131 	u8         log_tx_psn_win[0x6];
132 	u8         lro_log_timeout3[0x4];
133 	u8         lro_log_timeout2[0x4];
134 	u8         lro_log_timeout1[0x4];
135 	u8         lro_log_timeout0[0x4];
136 };
137 
138 struct mlx5_ifc_nv_sw_offload_cap_bits {
139 	u8         reserved_at_0[0x19];
140 	u8         swp_l4_csum_mode_l4_only[0x1];
141 	u8         reserved_at_1a[0x6];
142 };
143 
144 struct mlx5_ifc_nv_sw_accelerate_conf_bits {
145 	u8         swp_l4_csum_mode[0x2];
146 	u8         reserved_at_2[0x3e];
147 };
148 
149 #define MNVDA_HDR_SZ \
150 	(MLX5_ST_SZ_BYTES(mnvda_reg) - \
151 	 MLX5_BYTE_OFF(mnvda_reg, configuration_item_data))
152 
153 #define MLX5_SET_CFG_ITEM_TYPE(_cls_name, _mnvda_ptr, _field, _val) \
154 	MLX5_SET(mnvda_reg, _mnvda_ptr, \
155 		 configuration_item_header.type.configuration_item_type_class_##_cls_name._field, \
156 		 _val)
157 
158 #define MLX5_SET_CFG_HDR_LEN(_mnvda_ptr, _cls_name) \
159 	MLX5_SET(mnvda_reg, _mnvda_ptr, configuration_item_header.length, \
160 		 MLX5_ST_SZ_BYTES(_cls_name))
161 
162 #define MLX5_GET_CFG_HDR_LEN(_mnvda_ptr) \
163 	MLX5_GET(mnvda_reg, _mnvda_ptr, configuration_item_header.length)
164 
165 #define MLX5_DEFAULT_LOG_SF_BAR_SIZE 12
166 
mlx5_nv_param_read(struct mlx5_core_dev * dev,void * mnvda,size_t len)167 static int mlx5_nv_param_read(struct mlx5_core_dev *dev, void *mnvda,
168 			      size_t len)
169 {
170 	u32 param_idx, type_class;
171 	u32 header_len;
172 	void *cls_ptr;
173 	int err;
174 
175 	if (WARN_ON(len > MLX5_ST_SZ_BYTES(mnvda_reg)) || len < MNVDA_HDR_SZ)
176 		return -EINVAL; /* A caller bug */
177 
178 	err = mlx5_core_access_reg(dev, mnvda, len, mnvda, len, MLX5_REG_MNVDA,
179 				   0, 0);
180 	if (!err)
181 		return 0;
182 
183 	cls_ptr = MLX5_ADDR_OF(mnvda_reg, mnvda,
184 			       configuration_item_header.type.configuration_item_type_class_global);
185 
186 	type_class = MLX5_GET(configuration_item_type_class_global, cls_ptr,
187 			      type_class);
188 	param_idx = MLX5_GET(configuration_item_type_class_global, cls_ptr,
189 			     parameter_index);
190 	header_len = MLX5_GET_CFG_HDR_LEN(mnvda);
191 
192 	mlx5_core_warn(dev, "Failed to read mnvda reg: type_class 0x%x, param_idx 0x%x, header_len %u, err %d\n",
193 		       type_class, param_idx, header_len, err);
194 
195 	return -EOPNOTSUPP;
196 }
197 
mlx5_nv_param_write(struct mlx5_core_dev * dev,void * mnvda,size_t len)198 static int mlx5_nv_param_write(struct mlx5_core_dev *dev, void *mnvda,
199 			       size_t len)
200 {
201 	if (WARN_ON(len > MLX5_ST_SZ_BYTES(mnvda_reg)) || len < MNVDA_HDR_SZ)
202 		return -EINVAL;
203 
204 	if (WARN_ON(MLX5_GET_CFG_HDR_LEN(mnvda) == 0))
205 		return -EINVAL;
206 
207 	return mlx5_core_access_reg(dev, mnvda, len, mnvda, len, MLX5_REG_MNVDA,
208 				    0, 1);
209 }
210 
211 static int
mlx5_nv_param_read_sw_offload_conf(struct mlx5_core_dev * dev,void * mnvda,size_t len)212 mlx5_nv_param_read_sw_offload_conf(struct mlx5_core_dev *dev, void *mnvda,
213 				   size_t len)
214 {
215 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, type_class, 0);
216 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, parameter_index,
217 			       MLX5_CLASS_0_CTRL_ID_NV_SW_OFFLOAD_CONFIG);
218 	MLX5_SET_CFG_HDR_LEN(mnvda, nv_sw_offload_conf);
219 
220 	return mlx5_nv_param_read(dev, mnvda, len);
221 }
222 
223 static int
mlx5_nv_param_read_sw_offload_cap(struct mlx5_core_dev * dev,void * mnvda,size_t len)224 mlx5_nv_param_read_sw_offload_cap(struct mlx5_core_dev *dev, void *mnvda,
225 				  size_t len)
226 {
227 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, type_class, 0);
228 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, parameter_index,
229 			       MLX5_CLASS_0_CTRL_ID_NV_SW_OFFLOAD_CAP);
230 	MLX5_SET_CFG_HDR_LEN(mnvda, nv_sw_offload_cap);
231 
232 	return mlx5_nv_param_read(dev, mnvda, len);
233 }
234 
235 static int
mlx5_nv_param_read_sw_accelerate_conf(struct mlx5_core_dev * dev,void * mnvda,size_t len,int access_mode)236 mlx5_nv_param_read_sw_accelerate_conf(struct mlx5_core_dev *dev, void *mnvda,
237 				      size_t len, int access_mode)
238 {
239 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, type_class, 0);
240 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, parameter_index,
241 			       MLX5_CLASS_0_CTRL_ID_NV_SW_ACCELERATE_CONF);
242 	MLX5_SET_CFG_HDR_LEN(mnvda, nv_sw_accelerate_conf);
243 	MLX5_SET(mnvda_reg, mnvda, configuration_item_header.access_mode,
244 		 access_mode);
245 
246 	return mlx5_nv_param_read(dev, mnvda, len);
247 }
248 
249 static const char *const
250 	cqe_compress_str[] = { "balanced", "aggressive" };
251 
252 static int
mlx5_nv_param_devlink_cqe_compress_get(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)253 mlx5_nv_param_devlink_cqe_compress_get(struct devlink *devlink, u32 id,
254 				       struct devlink_param_gset_ctx *ctx,
255 				       struct netlink_ext_ack *extack)
256 {
257 	struct mlx5_core_dev *dev = devlink_priv(devlink);
258 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
259 	u8 value = U8_MAX;
260 	void *data;
261 	int err;
262 
263 	err = mlx5_nv_param_read_sw_offload_conf(dev, mnvda, sizeof(mnvda));
264 	if (err)
265 		return err;
266 
267 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
268 	value = MLX5_GET(nv_sw_offload_conf, data, cqe_compression);
269 
270 	if (value >= ARRAY_SIZE(cqe_compress_str))
271 		return -EOPNOTSUPP;
272 
273 	strscpy(ctx->val.vstr, cqe_compress_str[value], sizeof(ctx->val.vstr));
274 	return 0;
275 }
276 
277 static int
mlx5_nv_param_devlink_cqe_compress_validate(struct devlink * devlink,u32 id,union devlink_param_value * val,struct netlink_ext_ack * extack)278 mlx5_nv_param_devlink_cqe_compress_validate(struct devlink *devlink, u32 id,
279 					    union devlink_param_value *val,
280 					    struct netlink_ext_ack *extack)
281 {
282 	int i;
283 
284 	for (i = 0; i < ARRAY_SIZE(cqe_compress_str); i++) {
285 		if (!strcmp(val->vstr, cqe_compress_str[i]))
286 			return 0;
287 	}
288 
289 	NL_SET_ERR_MSG_MOD(extack,
290 			   "Invalid value, supported values are balanced/aggressive");
291 	return -EOPNOTSUPP;
292 }
293 
294 static int
mlx5_nv_param_devlink_cqe_compress_set(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)295 mlx5_nv_param_devlink_cqe_compress_set(struct devlink *devlink, u32 id,
296 				       struct devlink_param_gset_ctx *ctx,
297 				       struct netlink_ext_ack *extack)
298 {
299 	struct mlx5_core_dev *dev = devlink_priv(devlink);
300 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
301 	int err = 0;
302 	void *data;
303 	u8 value;
304 
305 	if (!strcmp(ctx->val.vstr, "aggressive"))
306 		value = 1;
307 	else /* balanced: can't be anything else already validated above */
308 		value = 0;
309 
310 	err = mlx5_nv_param_read_sw_offload_conf(dev, mnvda, sizeof(mnvda));
311 	if (err) {
312 		NL_SET_ERR_MSG_MOD(extack,
313 				   "Failed to read sw_offload_conf mnvda reg");
314 		return err;
315 	}
316 
317 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
318 	MLX5_SET(nv_sw_offload_conf, data, cqe_compression, value);
319 
320 	return mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
321 }
322 
323 enum swp_l4_csum_mode {
324 	SWP_L4_CSUM_MODE_DEFAULT = 0,
325 	SWP_L4_CSUM_MODE_FULL_CSUM = 1,
326 	SWP_L4_CSUM_MODE_L4_ONLY = 2,
327 };
328 
329 static const char *const
330 	swp_l4_csum_mode_str[] = { "default", "full_csum", "l4_only" };
331 
332 static int
mlx5_swp_l4_csum_mode_get(struct devlink * devlink,u32 id,int access_mode,u8 * value,struct netlink_ext_ack * extack)333 mlx5_swp_l4_csum_mode_get(struct devlink *devlink, u32 id,
334 			  int access_mode, u8 *value,
335 			  struct netlink_ext_ack *extack)
336 {
337 	struct mlx5_core_dev *dev = devlink_priv(devlink);
338 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
339 	void *data;
340 	int err;
341 
342 	err = mlx5_nv_param_read_sw_accelerate_conf(dev, mnvda, sizeof(mnvda),
343 						    access_mode);
344 	if (err) {
345 		NL_SET_ERR_MSG_MOD(extack,
346 				   "Failed to read sw_accelerate_conf mnvda reg");
347 		return err;
348 	}
349 
350 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
351 	*value = MLX5_GET(nv_sw_accelerate_conf, data, swp_l4_csum_mode);
352 
353 	if (*value >= ARRAY_SIZE(swp_l4_csum_mode_str)) {
354 		NL_SET_ERR_MSG_FMT_MOD(extack,
355 				       "Invalid swp_l4_csum_mode value %u read from device",
356 				       *value);
357 		return -EINVAL;
358 	}
359 
360 	return 0;
361 }
362 
363 static int
mlx5_devlink_swp_l4_csum_mode_get(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)364 mlx5_devlink_swp_l4_csum_mode_get(struct devlink *devlink, u32 id,
365 				  struct devlink_param_gset_ctx *ctx,
366 				  struct netlink_ext_ack *extack)
367 {
368 	u8 value;
369 	int err;
370 
371 	err = mlx5_swp_l4_csum_mode_get(devlink, id, MLX5_ACCESS_MODE_NEXT,
372 					&value, extack);
373 	if (err)
374 		return err;
375 
376 	strscpy(ctx->val.vstr, swp_l4_csum_mode_str[value],
377 		sizeof(ctx->val.vstr));
378 	return 0;
379 }
380 
381 static int
mlx5_devlink_swp_l4_csum_mode_validate(struct devlink * devlink,u32 id,union devlink_param_value * val,struct netlink_ext_ack * extack)382 mlx5_devlink_swp_l4_csum_mode_validate(struct devlink *devlink, u32 id,
383 				       union devlink_param_value *val,
384 				       struct netlink_ext_ack *extack)
385 {
386 	struct mlx5_core_dev *dev = devlink_priv(devlink);
387 	u32 cap[MLX5_ST_SZ_DW(mnvda_reg)] = {};
388 	void *data;
389 	int err, i;
390 
391 	for (i = 0; i < ARRAY_SIZE(swp_l4_csum_mode_str); i++) {
392 		if (!strcmp(val->vstr, swp_l4_csum_mode_str[i]))
393 			break;
394 	}
395 
396 	if (i >= ARRAY_SIZE(swp_l4_csum_mode_str) ||
397 	    i == SWP_L4_CSUM_MODE_DEFAULT) {
398 		NL_SET_ERR_MSG_MOD(extack,
399 				   "Invalid value, supported values are full_csum/l4_only");
400 		return -EINVAL;
401 	}
402 
403 	if (i == SWP_L4_CSUM_MODE_L4_ONLY) {
404 		err = mlx5_nv_param_read_sw_offload_cap(dev, cap, sizeof(cap));
405 		if (err) {
406 			NL_SET_ERR_MSG_MOD(extack,
407 					   "Failed to read sw_offload_cap");
408 			return err;
409 		}
410 
411 		data = MLX5_ADDR_OF(mnvda_reg, cap, configuration_item_data);
412 		if (!MLX5_GET(nv_sw_offload_cap, data, swp_l4_csum_mode_l4_only)) {
413 			NL_SET_ERR_MSG_MOD(extack,
414 					   "l4_only mode is not supported on this device");
415 			return -EOPNOTSUPP;
416 		}
417 	}
418 
419 	return 0;
420 }
421 
422 static int
mlx5_swp_l4_csum_mode_set(struct devlink * devlink,u32 id,u8 value,struct netlink_ext_ack * extack)423 mlx5_swp_l4_csum_mode_set(struct devlink *devlink, u32 id, u8 value,
424 			  struct netlink_ext_ack *extack)
425 {
426 	struct mlx5_core_dev *dev = devlink_priv(devlink);
427 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
428 	void *data;
429 	int err;
430 
431 	err = mlx5_nv_param_read_sw_accelerate_conf(dev, mnvda, sizeof(mnvda),
432 						    MLX5_ACCESS_MODE_NEXT);
433 	if (err) {
434 		NL_SET_ERR_MSG_MOD(extack,
435 				   "Failed to read sw_accelerate_conf mnvda reg");
436 		return err;
437 	}
438 
439 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
440 	MLX5_SET(nv_sw_accelerate_conf, data, swp_l4_csum_mode, value);
441 
442 	err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
443 	if (err)
444 		NL_SET_ERR_MSG_MOD(extack,
445 				   "Failed to write sw_accelerate_conf mnvda reg");
446 
447 	return err;
448 }
449 
450 static int
mlx5_devlink_swp_l4_csum_mode_set(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)451 mlx5_devlink_swp_l4_csum_mode_set(struct devlink *devlink, u32 id,
452 				  struct devlink_param_gset_ctx *ctx,
453 				  struct netlink_ext_ack *extack)
454 {
455 	u8 value;
456 
457 	if (!strcmp(ctx->val.vstr, "full_csum"))
458 		value = SWP_L4_CSUM_MODE_FULL_CSUM;
459 	else
460 		value = SWP_L4_CSUM_MODE_L4_ONLY;
461 
462 	return mlx5_swp_l4_csum_mode_set(devlink, id, value, extack);
463 }
464 
465 static int
mlx5_devlink_swp_l4_csum_mode_get_default(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)466 mlx5_devlink_swp_l4_csum_mode_get_default(struct devlink *devlink, u32 id,
467 					  struct devlink_param_gset_ctx *ctx,
468 					  struct netlink_ext_ack *extack)
469 {
470 	u8 value;
471 	int err;
472 
473 	err = mlx5_swp_l4_csum_mode_get(devlink, id, MLX5_ACCESS_MODE_DEFAULT,
474 					&value, extack);
475 	if (err)
476 		return err;
477 
478 	strscpy(ctx->val.vstr, swp_l4_csum_mode_str[value],
479 		sizeof(ctx->val.vstr));
480 	return 0;
481 }
482 
483 static int
mlx5_devlink_swp_l4_csum_mode_set_default(struct devlink * devlink,u32 id,enum devlink_param_cmode cmode,struct netlink_ext_ack * extack)484 mlx5_devlink_swp_l4_csum_mode_set_default(struct devlink *devlink, u32 id,
485 					  enum devlink_param_cmode cmode,
486 					  struct netlink_ext_ack *extack)
487 {
488 	u8 value;
489 	int err;
490 
491 	err = mlx5_swp_l4_csum_mode_get(devlink, id, MLX5_ACCESS_MODE_DEFAULT,
492 					&value, extack);
493 	if (err)
494 		return err;
495 
496 	return mlx5_swp_l4_csum_mode_set(devlink, id, value, extack);
497 }
498 
mlx5_nv_param_read_global_pci_conf(struct mlx5_core_dev * dev,void * mnvda,size_t len)499 static int mlx5_nv_param_read_global_pci_conf(struct mlx5_core_dev *dev,
500 					      void *mnvda, size_t len)
501 {
502 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, type_class, 0);
503 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, parameter_index,
504 			       MLX5_CLASS_0_CTRL_ID_NV_GLOBAL_PCI_CONF);
505 	MLX5_SET_CFG_HDR_LEN(mnvda, nv_global_pci_conf);
506 
507 	return mlx5_nv_param_read(dev, mnvda, len);
508 }
509 
mlx5_nv_param_read_global_pci_cap(struct mlx5_core_dev * dev,void * mnvda,size_t len)510 static int mlx5_nv_param_read_global_pci_cap(struct mlx5_core_dev *dev,
511 					     void *mnvda, size_t len)
512 {
513 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, type_class, 0);
514 	MLX5_SET_CFG_ITEM_TYPE(global, mnvda, parameter_index,
515 			       MLX5_CLASS_0_CTRL_ID_NV_GLOBAL_PCI_CAP);
516 	MLX5_SET_CFG_HDR_LEN(mnvda, nv_global_pci_cap);
517 
518 	return mlx5_nv_param_read(dev, mnvda, len);
519 }
520 
mlx5_nv_param_read_per_host_pf_conf(struct mlx5_core_dev * dev,void * mnvda,size_t len)521 static int mlx5_nv_param_read_per_host_pf_conf(struct mlx5_core_dev *dev,
522 					       void *mnvda, size_t len)
523 {
524 	MLX5_SET_CFG_ITEM_TYPE(per_host_pf, mnvda, type_class, 3);
525 	MLX5_SET_CFG_ITEM_TYPE(per_host_pf, mnvda, parameter_index,
526 			       MLX5_CLASS_3_CTRL_ID_NV_PF_PCI_CONF);
527 	MLX5_SET_CFG_HDR_LEN(mnvda, nv_pf_pci_conf);
528 
529 	return mlx5_nv_param_read(dev, mnvda, len);
530 }
531 
mlx5_devlink_enable_sriov_get(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)532 static int mlx5_devlink_enable_sriov_get(struct devlink *devlink, u32 id,
533 					 struct devlink_param_gset_ctx *ctx,
534 					 struct netlink_ext_ack *extack)
535 {
536 	struct mlx5_core_dev *dev = devlink_priv(devlink);
537 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
538 	bool sriov_en = false;
539 	void *data;
540 	int err;
541 
542 	err = mlx5_nv_param_read_global_pci_cap(dev, mnvda, sizeof(mnvda));
543 	if (err)
544 		return err;
545 
546 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
547 	if (!MLX5_GET(nv_global_pci_cap, data, sriov_support)) {
548 		ctx->val.vbool = false;
549 		return 0;
550 	}
551 
552 	memset(mnvda, 0, sizeof(mnvda));
553 	err = mlx5_nv_param_read_global_pci_conf(dev, mnvda, sizeof(mnvda));
554 	if (err)
555 		return err;
556 
557 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
558 	sriov_en = MLX5_GET(nv_global_pci_conf, data, sriov_en);
559 	if (!MLX5_GET(nv_global_pci_conf, data, per_pf_total_vf)) {
560 		ctx->val.vbool = sriov_en;
561 		return 0;
562 	}
563 
564 	/* SRIOV is per PF */
565 	memset(mnvda, 0, sizeof(mnvda));
566 	err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
567 	if (err)
568 		return err;
569 
570 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
571 	ctx->val.vbool = sriov_en &&
572 			 MLX5_GET(nv_pf_pci_conf, data, pf_total_vf_en);
573 	return 0;
574 }
575 
mlx5_devlink_enable_sriov_set(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)576 static int mlx5_devlink_enable_sriov_set(struct devlink *devlink, u32 id,
577 					 struct devlink_param_gset_ctx *ctx,
578 					 struct netlink_ext_ack *extack)
579 {
580 	struct mlx5_core_dev *dev = devlink_priv(devlink);
581 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
582 	bool per_pf_support;
583 	void *cap, *data;
584 	int err;
585 
586 	err = mlx5_nv_param_read_global_pci_cap(dev, mnvda, sizeof(mnvda));
587 	if (err) {
588 		NL_SET_ERR_MSG_MOD(extack,
589 				   "Failed to read global PCI capability");
590 		return err;
591 	}
592 
593 	cap = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
594 	per_pf_support = MLX5_GET(nv_global_pci_cap, cap,
595 				  per_pf_total_vf_supported);
596 
597 	if (!MLX5_GET(nv_global_pci_cap, cap, sriov_support)) {
598 		NL_SET_ERR_MSG_MOD(extack,
599 				   "SRIOV is not supported on this device");
600 		return -EOPNOTSUPP;
601 	}
602 
603 	if (!per_pf_support) {
604 		/* We don't allow global SRIOV setting on per PF devlink */
605 		NL_SET_ERR_MSG_MOD(extack,
606 				   "SRIOV is not per PF on this device");
607 		return -EOPNOTSUPP;
608 	}
609 
610 	memset(mnvda, 0, sizeof(mnvda));
611 	err = mlx5_nv_param_read_global_pci_conf(dev, mnvda, sizeof(mnvda));
612 	if (err) {
613 		NL_SET_ERR_MSG_MOD(extack,
614 				   "Unable to read global PCI configuration");
615 		return err;
616 	}
617 
618 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
619 
620 	/* setup per PF sriov mode */
621 	MLX5_SET(nv_global_pci_conf, data, sriov_valid, 1);
622 	MLX5_SET(nv_global_pci_conf, data, sriov_en, 1);
623 	MLX5_SET(nv_global_pci_conf, data, per_pf_total_vf, 1);
624 
625 	err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
626 	if (err) {
627 		NL_SET_ERR_MSG_MOD(extack,
628 				   "Unable to write global PCI configuration");
629 		return err;
630 	}
631 
632 	/* enable/disable sriov on this PF */
633 	memset(mnvda, 0, sizeof(mnvda));
634 	err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
635 	if (err) {
636 		NL_SET_ERR_MSG_MOD(extack,
637 				   "Unable to read per host PF configuration");
638 		return err;
639 	}
640 	MLX5_SET(nv_pf_pci_conf, data, pf_total_vf_en, ctx->val.vbool);
641 	return mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
642 }
643 
mlx5_devlink_total_vfs_get(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)644 static int mlx5_devlink_total_vfs_get(struct devlink *devlink, u32 id,
645 				      struct devlink_param_gset_ctx *ctx,
646 				      struct netlink_ext_ack *extack)
647 {
648 	struct mlx5_core_dev *dev = devlink_priv(devlink);
649 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
650 	void *data;
651 	int err;
652 
653 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
654 
655 	err = mlx5_nv_param_read_global_pci_cap(dev, mnvda, sizeof(mnvda));
656 	if (err)
657 		return err;
658 
659 	if (!MLX5_GET(nv_global_pci_cap, data, sriov_support)) {
660 		ctx->val.vu32 = 0;
661 		return 0;
662 	}
663 
664 	memset(mnvda, 0, sizeof(mnvda));
665 	err = mlx5_nv_param_read_global_pci_conf(dev, mnvda, sizeof(mnvda));
666 	if (err)
667 		return err;
668 
669 	if (!MLX5_GET(nv_global_pci_conf, data, per_pf_total_vf)) {
670 		ctx->val.vu32 = MLX5_GET(nv_global_pci_conf, data, total_vfs);
671 		return 0;
672 	}
673 
674 	/* SRIOV is per PF */
675 	memset(mnvda, 0, sizeof(mnvda));
676 	err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
677 	if (err)
678 		return err;
679 
680 	ctx->val.vu32 = MLX5_GET(nv_pf_pci_conf, data, total_vf);
681 
682 	return 0;
683 }
684 
mlx5_devlink_total_vfs_set(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)685 static int mlx5_devlink_total_vfs_set(struct devlink *devlink, u32 id,
686 				      struct devlink_param_gset_ctx *ctx,
687 				      struct netlink_ext_ack *extack)
688 {
689 	struct mlx5_core_dev *dev = devlink_priv(devlink);
690 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)];
691 	void *data;
692 	int err;
693 
694 	err = mlx5_nv_param_read_global_pci_cap(dev, mnvda, sizeof(mnvda));
695 	if (err) {
696 		NL_SET_ERR_MSG_MOD(extack, "Failed to read global pci cap");
697 		return err;
698 	}
699 
700 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
701 	if (!MLX5_GET(nv_global_pci_cap, data, sriov_support)) {
702 		NL_SET_ERR_MSG_MOD(extack, "Not configurable on this device");
703 		return -EOPNOTSUPP;
704 	}
705 
706 	if (!MLX5_GET(nv_global_pci_cap, data, per_pf_total_vf_supported)) {
707 		/* We don't allow global SRIOV setting on per PF devlink */
708 		NL_SET_ERR_MSG_MOD(extack,
709 				   "SRIOV is not per PF on this device");
710 		return -EOPNOTSUPP;
711 	}
712 
713 	memset(mnvda, 0, sizeof(mnvda));
714 	err = mlx5_nv_param_read_global_pci_conf(dev, mnvda, sizeof(mnvda));
715 	if (err)
716 		return err;
717 
718 	MLX5_SET(nv_global_pci_conf, data, sriov_valid, 1);
719 	MLX5_SET(nv_global_pci_conf, data, per_pf_total_vf, 1);
720 
721 	err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
722 	if (err)
723 		return err;
724 
725 	memset(mnvda, 0, sizeof(mnvda));
726 	err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
727 	if (err)
728 		return err;
729 
730 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
731 	MLX5_SET(nv_pf_pci_conf, data, total_vf, ctx->val.vu32);
732 	return mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
733 }
734 
mlx5_devlink_total_vfs_validate(struct devlink * devlink,u32 id,union devlink_param_value * val,struct netlink_ext_ack * extack)735 static int mlx5_devlink_total_vfs_validate(struct devlink *devlink, u32 id,
736 					   union devlink_param_value *val,
737 					   struct netlink_ext_ack *extack)
738 {
739 	struct mlx5_core_dev *dev = devlink_priv(devlink);
740 	u32 cap[MLX5_ST_SZ_DW(mnvda_reg)];
741 	void *data;
742 	u16 max;
743 	int err;
744 
745 	data = MLX5_ADDR_OF(mnvda_reg, cap, configuration_item_data);
746 
747 	err = mlx5_nv_param_read_global_pci_cap(dev, cap, sizeof(cap));
748 	if (err)
749 		return err;
750 
751 	if (!MLX5_GET(nv_global_pci_cap, data, max_vfs_per_pf_valid))
752 		return 0; /* optimistic, but set might fail later */
753 
754 	max = MLX5_GET(nv_global_pci_cap, data, max_vfs_per_pf);
755 	if (val->vu16 > max) {
756 		NL_SET_ERR_MSG_FMT_MOD(extack,
757 				       "Max allowed by device is %u", max);
758 		return -EINVAL;
759 	}
760 
761 	return 0;
762 }
763 
mlx5_devlink_max_sfs_get(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)764 static int mlx5_devlink_max_sfs_get(struct devlink *devlink, u32 id,
765 				    struct devlink_param_gset_ctx *ctx,
766 				    struct netlink_ext_ack *extack)
767 {
768 	struct mlx5_core_dev *dev = devlink_priv(devlink);
769 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
770 	void *data;
771 	int err;
772 
773 	err = mlx5_nv_param_read_global_pci_conf(dev, mnvda, sizeof(mnvda));
774 	if (err) {
775 		NL_SET_ERR_MSG_MOD(extack,
776 				   "Failed to read global PCI configuration");
777 		return err;
778 	}
779 
780 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
781 	if (!MLX5_GET(nv_global_pci_conf, data, per_pf_num_sf)) {
782 		ctx->val.vu32 = 0;
783 		return 0;
784 	}
785 
786 	memset(mnvda, 0, sizeof(mnvda));
787 	err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
788 	if (err) {
789 		NL_SET_ERR_MSG_MOD(extack, "Failed to read PF configuration");
790 		return err;
791 	}
792 
793 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
794 	if (MLX5_GET(nv_pf_pci_conf, data, pf_total_sf_en))
795 		ctx->val.vu32 = MLX5_GET(nv_pf_pci_conf, data, total_sf);
796 	else
797 		ctx->val.vu32 = 0;
798 
799 	return 0;
800 }
801 
mlx5_devlink_max_sfs_validate(struct devlink * devlink,u32 id,union devlink_param_value * val,struct netlink_ext_ack * extack)802 static int mlx5_devlink_max_sfs_validate(struct devlink *devlink, u32 id,
803 					 union devlink_param_value *val,
804 					 struct netlink_ext_ack *extack)
805 {
806 	if (val->vu32 > U16_MAX) {
807 		NL_SET_ERR_MSG_FMT_MOD(extack,
808 				       "Max SFs allowed value is %u", U16_MAX);
809 		return -EINVAL;
810 	}
811 
812 	return 0;
813 }
814 
mlx5_devlink_max_sfs_set(struct devlink * devlink,u32 id,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)815 static int mlx5_devlink_max_sfs_set(struct devlink *devlink, u32 id,
816 				    struct devlink_param_gset_ctx *ctx,
817 				    struct netlink_ext_ack *extack)
818 {
819 	struct mlx5_core_dev *dev = devlink_priv(devlink);
820 	u32 mnvda[MLX5_ST_SZ_DW(mnvda_reg)] = {};
821 	void *data;
822 	int err;
823 
824 	/* we don't explicitly disable per_pf_num_sf when max_sfs is 0 because
825 	 * another PF may be using SFs
826 	 */
827 	if (ctx->val.vu32) {
828 		err = mlx5_nv_param_read_global_pci_conf(dev, mnvda,
829 							 sizeof(mnvda));
830 		if (err) {
831 			NL_SET_ERR_MSG_MOD(extack,
832 					   "Failed to read global PCI configuration");
833 			return err;
834 		}
835 
836 		data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
837 		/* always enable per_pf_num_sf because another PF may use SFs */
838 		MLX5_SET(nv_global_pci_conf, data, per_pf_num_sf, 1);
839 
840 		err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
841 		if (err) {
842 			NL_SET_ERR_MSG_MOD(extack,
843 					   "Failed to change per_pf_num_sf global PCI configuration");
844 			return err;
845 		}
846 		memset(mnvda, 0, sizeof(mnvda));
847 	}
848 
849 	err = mlx5_nv_param_read_per_host_pf_conf(dev, mnvda, sizeof(mnvda));
850 	if (err) {
851 		NL_SET_ERR_MSG_MOD(extack, "Failed to read PF configuration");
852 		return err;
853 	}
854 
855 	data = MLX5_ADDR_OF(mnvda_reg, mnvda, configuration_item_data);
856 	MLX5_SET(nv_pf_pci_conf, data, log_sf_bar_size,
857 		 ctx->val.vu32 ? MLX5_DEFAULT_LOG_SF_BAR_SIZE : 0);
858 	MLX5_SET(nv_pf_pci_conf, data, pf_total_sf_en, !!ctx->val.vu32);
859 	MLX5_SET(nv_pf_pci_conf, data, total_sf, ctx->val.vu32);
860 
861 	err = mlx5_nv_param_write(dev, mnvda, sizeof(mnvda));
862 	if (err) {
863 		NL_SET_ERR_MSG_MOD(extack,
864 				   "Failed to change PF PCI configuration");
865 		return err;
866 	}
867 	NL_SET_ERR_MSG_MOD(extack,
868 			   "Modifying max_sfs requires a FW reset and PCI bus rescan");
869 
870 	return 0;
871 }
872 
873 static const struct devlink_param mlx5_nv_param_devlink_params[] = {
874 	DEVLINK_PARAM_GENERIC(ENABLE_SRIOV, BIT(DEVLINK_PARAM_CMODE_PERMANENT),
875 			      mlx5_devlink_enable_sriov_get,
876 			      mlx5_devlink_enable_sriov_set, NULL),
877 	DEVLINK_PARAM_GENERIC(TOTAL_VFS, BIT(DEVLINK_PARAM_CMODE_PERMANENT),
878 			      mlx5_devlink_total_vfs_get,
879 			      mlx5_devlink_total_vfs_set,
880 			      mlx5_devlink_total_vfs_validate),
881 	DEVLINK_PARAM_GENERIC(MAX_SFS, BIT(DEVLINK_PARAM_CMODE_PERMANENT),
882 			      mlx5_devlink_max_sfs_get,
883 			      mlx5_devlink_max_sfs_set,
884 			      mlx5_devlink_max_sfs_validate),
885 	DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_CQE_COMPRESSION_TYPE,
886 			     "cqe_compress_type", DEVLINK_PARAM_TYPE_STRING,
887 			     BIT(DEVLINK_PARAM_CMODE_PERMANENT),
888 			     mlx5_nv_param_devlink_cqe_compress_get,
889 			     mlx5_nv_param_devlink_cqe_compress_set,
890 			     mlx5_nv_param_devlink_cqe_compress_validate),
891 	DEVLINK_PARAM_DRIVER_WITH_DEFAULTS(MLX5_DEVLINK_PARAM_ID_SWP_L4_CSUM_MODE,
892 					   "swp_l4_csum_mode", DEVLINK_PARAM_TYPE_STRING,
893 					   BIT(DEVLINK_PARAM_CMODE_PERMANENT),
894 					   mlx5_devlink_swp_l4_csum_mode_get,
895 					   mlx5_devlink_swp_l4_csum_mode_set,
896 					   mlx5_devlink_swp_l4_csum_mode_validate,
897 					   mlx5_devlink_swp_l4_csum_mode_get_default,
898 					   mlx5_devlink_swp_l4_csum_mode_set_default),
899 };
900 
mlx5_nv_param_register_dl_params(struct devlink * devlink)901 int mlx5_nv_param_register_dl_params(struct devlink *devlink)
902 {
903 	if (!mlx5_core_is_pf(devlink_priv(devlink)))
904 		return 0;
905 
906 	return devl_params_register(devlink, mlx5_nv_param_devlink_params,
907 				    ARRAY_SIZE(mlx5_nv_param_devlink_params));
908 }
909 
mlx5_nv_param_unregister_dl_params(struct devlink * devlink)910 void mlx5_nv_param_unregister_dl_params(struct devlink *devlink)
911 {
912 	if (!mlx5_core_is_pf(devlink_priv(devlink)))
913 		return;
914 
915 	devl_params_unregister(devlink, mlx5_nv_param_devlink_params,
916 			       ARRAY_SIZE(mlx5_nv_param_devlink_params));
917 }
918 
919