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