hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
....@@ -9,31 +9,569 @@
99
1010 #include <linux/pci.h>
1111 #include <linux/netdevice.h>
12
+#include <net/devlink.h>
1213 #include "bnxt_hsi.h"
1314 #include "bnxt.h"
1415 #include "bnxt_vfr.h"
1516 #include "bnxt_devlink.h"
17
+#include "bnxt_ethtool.h"
18
+
19
+static int
20
+bnxt_dl_flash_update(struct devlink *dl,
21
+ struct devlink_flash_update_params *params,
22
+ struct netlink_ext_ack *extack)
23
+{
24
+ struct bnxt *bp = bnxt_get_bp_from_dl(dl);
25
+ int rc;
26
+
27
+ if (!BNXT_PF(bp)) {
28
+ NL_SET_ERR_MSG_MOD(extack,
29
+ "flash update not supported from a VF");
30
+ return -EPERM;
31
+ }
32
+
33
+ devlink_flash_update_begin_notify(dl);
34
+ devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0);
35
+ rc = bnxt_flash_package_from_file(bp->dev, params->file_name, 0);
36
+ if (!rc)
37
+ devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0);
38
+ else
39
+ devlink_flash_update_status_notify(dl, "Flashing failed", NULL, 0, 0);
40
+ devlink_flash_update_end_notify(dl);
41
+ return rc;
42
+}
43
+
44
+static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
45
+ struct devlink_fmsg *fmsg,
46
+ struct netlink_ext_ack *extack)
47
+{
48
+ struct bnxt *bp = devlink_health_reporter_priv(reporter);
49
+ u32 val, health_status;
50
+ int rc;
51
+
52
+ if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
53
+ return 0;
54
+
55
+ val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
56
+ health_status = val & 0xffff;
57
+
58
+ if (health_status < BNXT_FW_STATUS_HEALTHY) {
59
+ rc = devlink_fmsg_string_pair_put(fmsg, "Description",
60
+ "Not yet completed initialization");
61
+ if (rc)
62
+ return rc;
63
+ } else if (health_status > BNXT_FW_STATUS_HEALTHY) {
64
+ rc = devlink_fmsg_string_pair_put(fmsg, "Description",
65
+ "Encountered fatal error and cannot recover");
66
+ if (rc)
67
+ return rc;
68
+ }
69
+
70
+ if (val >> 16) {
71
+ rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16);
72
+ if (rc)
73
+ return rc;
74
+ }
75
+
76
+ val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
77
+ rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val);
78
+ if (rc)
79
+ return rc;
80
+
81
+ return 0;
82
+}
83
+
84
+static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
85
+ .name = "fw",
86
+ .diagnose = bnxt_fw_reporter_diagnose,
87
+};
88
+
89
+static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
90
+ void *priv_ctx,
91
+ struct netlink_ext_ack *extack)
92
+{
93
+ struct bnxt *bp = devlink_health_reporter_priv(reporter);
94
+
95
+ if (!priv_ctx)
96
+ return -EOPNOTSUPP;
97
+
98
+ bnxt_fw_reset(bp);
99
+ return -EINPROGRESS;
100
+}
101
+
102
+static const
103
+struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
104
+ .name = "fw_reset",
105
+ .recover = bnxt_fw_reset_recover,
106
+};
107
+
108
+static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter,
109
+ void *priv_ctx,
110
+ struct netlink_ext_ack *extack)
111
+{
112
+ struct bnxt *bp = devlink_health_reporter_priv(reporter);
113
+ struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
114
+ unsigned long event;
115
+
116
+ if (!priv_ctx)
117
+ return -EOPNOTSUPP;
118
+
119
+ bp->fw_health->fatal = true;
120
+ event = fw_reporter_ctx->sp_event;
121
+ if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT)
122
+ bnxt_fw_reset(bp);
123
+ else if (event == BNXT_FW_EXCEPTION_SP_EVENT)
124
+ bnxt_fw_exception(bp);
125
+
126
+ return -EINPROGRESS;
127
+}
128
+
129
+static const
130
+struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = {
131
+ .name = "fw_fatal",
132
+ .recover = bnxt_fw_fatal_recover,
133
+};
134
+
135
+void bnxt_dl_fw_reporters_create(struct bnxt *bp)
136
+{
137
+ struct bnxt_fw_health *health = bp->fw_health;
138
+
139
+ if (!bp->dl || !health)
140
+ return;
141
+
142
+ if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
143
+ goto err_recovery;
144
+
145
+ health->fw_reset_reporter =
146
+ devlink_health_reporter_create(bp->dl,
147
+ &bnxt_dl_fw_reset_reporter_ops,
148
+ 0, bp);
149
+ if (IS_ERR(health->fw_reset_reporter)) {
150
+ netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
151
+ PTR_ERR(health->fw_reset_reporter));
152
+ health->fw_reset_reporter = NULL;
153
+ bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
154
+ }
155
+
156
+err_recovery:
157
+ if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
158
+ return;
159
+
160
+ if (!health->fw_reporter) {
161
+ health->fw_reporter =
162
+ devlink_health_reporter_create(bp->dl,
163
+ &bnxt_dl_fw_reporter_ops,
164
+ 0, bp);
165
+ if (IS_ERR(health->fw_reporter)) {
166
+ netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
167
+ PTR_ERR(health->fw_reporter));
168
+ health->fw_reporter = NULL;
169
+ bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
170
+ return;
171
+ }
172
+ }
173
+
174
+ if (health->fw_fatal_reporter)
175
+ return;
176
+
177
+ health->fw_fatal_reporter =
178
+ devlink_health_reporter_create(bp->dl,
179
+ &bnxt_dl_fw_fatal_reporter_ops,
180
+ 0, bp);
181
+ if (IS_ERR(health->fw_fatal_reporter)) {
182
+ netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
183
+ PTR_ERR(health->fw_fatal_reporter));
184
+ health->fw_fatal_reporter = NULL;
185
+ bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
186
+ }
187
+}
188
+
189
+void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
190
+{
191
+ struct bnxt_fw_health *health = bp->fw_health;
192
+
193
+ if (!bp->dl || !health)
194
+ return;
195
+
196
+ if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
197
+ health->fw_reset_reporter) {
198
+ devlink_health_reporter_destroy(health->fw_reset_reporter);
199
+ health->fw_reset_reporter = NULL;
200
+ }
201
+
202
+ if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all)
203
+ return;
204
+
205
+ if (health->fw_reporter) {
206
+ devlink_health_reporter_destroy(health->fw_reporter);
207
+ health->fw_reporter = NULL;
208
+ }
209
+
210
+ if (health->fw_fatal_reporter) {
211
+ devlink_health_reporter_destroy(health->fw_fatal_reporter);
212
+ health->fw_fatal_reporter = NULL;
213
+ }
214
+}
215
+
216
+void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
217
+{
218
+ struct bnxt_fw_health *fw_health = bp->fw_health;
219
+ struct bnxt_fw_reporter_ctx fw_reporter_ctx;
220
+
221
+ fw_reporter_ctx.sp_event = event;
222
+ switch (event) {
223
+ case BNXT_FW_RESET_NOTIFY_SP_EVENT:
224
+ if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) {
225
+ if (!fw_health->fw_fatal_reporter)
226
+ return;
227
+
228
+ devlink_health_report(fw_health->fw_fatal_reporter,
229
+ "FW fatal async event received",
230
+ &fw_reporter_ctx);
231
+ return;
232
+ }
233
+ if (!fw_health->fw_reset_reporter)
234
+ return;
235
+
236
+ devlink_health_report(fw_health->fw_reset_reporter,
237
+ "FW non-fatal reset event received",
238
+ &fw_reporter_ctx);
239
+ return;
240
+
241
+ case BNXT_FW_EXCEPTION_SP_EVENT:
242
+ if (!fw_health->fw_fatal_reporter)
243
+ return;
244
+
245
+ devlink_health_report(fw_health->fw_fatal_reporter,
246
+ "FW fatal error reported",
247
+ &fw_reporter_ctx);
248
+ return;
249
+ }
250
+}
251
+
252
+void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy)
253
+{
254
+ struct bnxt_fw_health *health = bp->fw_health;
255
+ u8 state;
256
+
257
+ if (healthy)
258
+ state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
259
+ else
260
+ state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
261
+
262
+ if (health->fatal)
263
+ devlink_health_reporter_state_update(health->fw_fatal_reporter,
264
+ state);
265
+ else
266
+ devlink_health_reporter_state_update(health->fw_reset_reporter,
267
+ state);
268
+
269
+ health->fatal = false;
270
+}
271
+
272
+void bnxt_dl_health_recovery_done(struct bnxt *bp)
273
+{
274
+ struct bnxt_fw_health *hlth = bp->fw_health;
275
+
276
+ if (hlth->fatal)
277
+ devlink_health_reporter_recovery_done(hlth->fw_fatal_reporter);
278
+ else
279
+ devlink_health_reporter_recovery_done(hlth->fw_reset_reporter);
280
+}
281
+
282
+static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
283
+ struct netlink_ext_ack *extack);
16284
17285 static const struct devlink_ops bnxt_dl_ops = {
18286 #ifdef CONFIG_BNXT_SRIOV
19287 .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
20288 .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
21289 #endif /* CONFIG_BNXT_SRIOV */
290
+ .info_get = bnxt_dl_info_get,
291
+ .flash_update = bnxt_dl_flash_update,
292
+};
293
+
294
+static const struct devlink_ops bnxt_vf_dl_ops;
295
+
296
+enum bnxt_dl_param_id {
297
+ BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
298
+ BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
22299 };
23300
24301 static const struct bnxt_dl_nvm_param nvm_params[] = {
25302 {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
26
- BNXT_NVM_SHARED_CFG, 1},
303
+ BNXT_NVM_SHARED_CFG, 1, 1},
304
+ {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
305
+ BNXT_NVM_SHARED_CFG, 1, 1},
306
+ {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
307
+ NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4},
308
+ {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
309
+ NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4},
310
+ {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
311
+ BNXT_NVM_SHARED_CFG, 1, 1},
27312 };
313
+
314
+union bnxt_nvm_data {
315
+ u8 val8;
316
+ __le32 val32;
317
+};
318
+
319
+static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst,
320
+ union devlink_param_value *src,
321
+ int nvm_num_bits, int dl_num_bytes)
322
+{
323
+ u32 val32 = 0;
324
+
325
+ if (nvm_num_bits == 1) {
326
+ dst->val8 = src->vbool;
327
+ return;
328
+ }
329
+ if (dl_num_bytes == 4)
330
+ val32 = src->vu32;
331
+ else if (dl_num_bytes == 2)
332
+ val32 = (u32)src->vu16;
333
+ else if (dl_num_bytes == 1)
334
+ val32 = (u32)src->vu8;
335
+ dst->val32 = cpu_to_le32(val32);
336
+}
337
+
338
+static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
339
+ union bnxt_nvm_data *src,
340
+ int nvm_num_bits, int dl_num_bytes)
341
+{
342
+ u32 val32;
343
+
344
+ if (nvm_num_bits == 1) {
345
+ dst->vbool = src->val8;
346
+ return;
347
+ }
348
+ val32 = le32_to_cpu(src->val32);
349
+ if (dl_num_bytes == 4)
350
+ dst->vu32 = val32;
351
+ else if (dl_num_bytes == 2)
352
+ dst->vu16 = (u16)val32;
353
+ else if (dl_num_bytes == 1)
354
+ dst->vu8 = (u8)val32;
355
+}
356
+
357
+static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp,
358
+ union devlink_param_value *nvm_cfg_ver)
359
+{
360
+ struct hwrm_nvm_get_variable_input req = {0};
361
+ union bnxt_nvm_data *data;
362
+ dma_addr_t data_dma_addr;
363
+ int rc;
364
+
365
+ bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
366
+ data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data),
367
+ &data_dma_addr, GFP_KERNEL);
368
+ if (!data)
369
+ return -ENOMEM;
370
+
371
+ req.dest_data_addr = cpu_to_le64(data_dma_addr);
372
+ req.data_len = cpu_to_le16(BNXT_NVM_CFG_VER_BITS);
373
+ req.option_num = cpu_to_le16(NVM_OFF_NVM_CFG_VER);
374
+
375
+ rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
376
+ if (!rc)
377
+ bnxt_copy_from_nvm_data(nvm_cfg_ver, data,
378
+ BNXT_NVM_CFG_VER_BITS,
379
+ BNXT_NVM_CFG_VER_BYTES);
380
+
381
+ dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
382
+ return rc;
383
+}
384
+
385
+static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req,
386
+ enum bnxt_dl_version_type type, const char *key,
387
+ char *buf)
388
+{
389
+ if (!strlen(buf))
390
+ return 0;
391
+
392
+ if ((bp->flags & BNXT_FLAG_CHIP_P5) &&
393
+ (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) ||
394
+ !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE)))
395
+ return 0;
396
+
397
+ switch (type) {
398
+ case BNXT_VERSION_FIXED:
399
+ return devlink_info_version_fixed_put(req, key, buf);
400
+ case BNXT_VERSION_RUNNING:
401
+ return devlink_info_version_running_put(req, key, buf);
402
+ case BNXT_VERSION_STORED:
403
+ return devlink_info_version_stored_put(req, key, buf);
404
+ }
405
+ return 0;
406
+}
407
+
408
+#define HWRM_FW_VER_STR_LEN 16
409
+
410
+static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
411
+ struct netlink_ext_ack *extack)
412
+{
413
+ struct hwrm_nvm_get_dev_info_output nvm_dev_info;
414
+ struct bnxt *bp = bnxt_get_bp_from_dl(dl);
415
+ union devlink_param_value nvm_cfg_ver;
416
+ struct hwrm_ver_get_output *ver_resp;
417
+ char mgmt_ver[FW_VER_STR_LEN];
418
+ char roce_ver[FW_VER_STR_LEN];
419
+ char ncsi_ver[FW_VER_STR_LEN];
420
+ char buf[32];
421
+ int rc;
422
+
423
+ rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME);
424
+ if (rc)
425
+ return rc;
426
+
427
+ if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) {
428
+ sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
429
+ bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4],
430
+ bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]);
431
+ rc = devlink_info_serial_number_put(req, buf);
432
+ if (rc)
433
+ return rc;
434
+ }
435
+
436
+ if (strlen(bp->board_serialno)) {
437
+ rc = devlink_info_board_serial_number_put(req, bp->board_serialno);
438
+ if (rc)
439
+ return rc;
440
+ }
441
+
442
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED,
443
+ DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
444
+ bp->board_partno);
445
+ if (rc)
446
+ return rc;
447
+
448
+ sprintf(buf, "%X", bp->chip_num);
449
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED,
450
+ DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf);
451
+ if (rc)
452
+ return rc;
453
+
454
+ ver_resp = &bp->ver_resp;
455
+ sprintf(buf, "%c%d", 'A' + ver_resp->chip_rev, ver_resp->chip_metal);
456
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED,
457
+ DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf);
458
+ if (rc)
459
+ return rc;
460
+
461
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
462
+ DEVLINK_INFO_VERSION_GENERIC_FW_PSID,
463
+ bp->nvm_cfg_ver);
464
+ if (rc)
465
+ return rc;
466
+
467
+ buf[0] = 0;
468
+ strncat(buf, ver_resp->active_pkg_name, HWRM_FW_VER_STR_LEN);
469
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
470
+ DEVLINK_INFO_VERSION_GENERIC_FW, buf);
471
+ if (rc)
472
+ return rc;
473
+
474
+ if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &nvm_cfg_ver)) {
475
+ u32 ver = nvm_cfg_ver.vu32;
476
+
477
+ sprintf(buf, "%d.%d.%d", (ver >> 16) & 0xff, (ver >> 8) & 0xff,
478
+ ver & 0xff);
479
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
480
+ DEVLINK_INFO_VERSION_GENERIC_FW_PSID,
481
+ buf);
482
+ if (rc)
483
+ return rc;
484
+ }
485
+
486
+ if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) {
487
+ snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
488
+ ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor,
489
+ ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch);
490
+
491
+ snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
492
+ ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor,
493
+ ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch);
494
+
495
+ snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
496
+ ver_resp->roce_fw_major, ver_resp->roce_fw_minor,
497
+ ver_resp->roce_fw_build, ver_resp->roce_fw_patch);
498
+ } else {
499
+ snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
500
+ ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b,
501
+ ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b);
502
+
503
+ snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
504
+ ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b,
505
+ ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b);
506
+
507
+ snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
508
+ ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b,
509
+ ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b);
510
+ }
511
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
512
+ DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
513
+ if (rc)
514
+ return rc;
515
+
516
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
517
+ DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
518
+ bp->hwrm_ver_supp);
519
+ if (rc)
520
+ return rc;
521
+
522
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
523
+ DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver);
524
+ if (rc)
525
+ return rc;
526
+
527
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
528
+ DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
529
+ if (rc)
530
+ return rc;
531
+
532
+ rc = bnxt_hwrm_nvm_get_dev_info(bp, &nvm_dev_info);
533
+ if (rc ||
534
+ !(nvm_dev_info.flags & NVM_GET_DEV_INFO_RESP_FLAGS_FW_VER_VALID))
535
+ return 0;
536
+
537
+ buf[0] = 0;
538
+ strncat(buf, nvm_dev_info.pkg_name, HWRM_FW_VER_STR_LEN);
539
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
540
+ DEVLINK_INFO_VERSION_GENERIC_FW, buf);
541
+ if (rc)
542
+ return rc;
543
+
544
+ snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
545
+ nvm_dev_info.hwrm_fw_major, nvm_dev_info.hwrm_fw_minor,
546
+ nvm_dev_info.hwrm_fw_build, nvm_dev_info.hwrm_fw_patch);
547
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
548
+ DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
549
+ if (rc)
550
+ return rc;
551
+
552
+ snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
553
+ nvm_dev_info.mgmt_fw_major, nvm_dev_info.mgmt_fw_minor,
554
+ nvm_dev_info.mgmt_fw_build, nvm_dev_info.mgmt_fw_patch);
555
+ rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
556
+ DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver);
557
+ if (rc)
558
+ return rc;
559
+
560
+ snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
561
+ nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor,
562
+ nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch);
563
+ return bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
564
+ DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
565
+}
28566
29567 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
30568 int msg_len, union devlink_param_value *val)
31569 {
32570 struct hwrm_nvm_get_variable_input *req = msg;
33
- void *data_addr = NULL, *buf = NULL;
34571 struct bnxt_dl_nvm_param nvm_param;
35
- int bytesize, idx = 0, rc, i;
572
+ union bnxt_nvm_data *data;
36573 dma_addr_t data_dma_addr;
574
+ int idx = 0, rc, i;
37575
38576 /* Get/Set NVM CFG parameter is supported only on PFs */
39577 if (BNXT_VF(bp))
....@@ -54,37 +592,41 @@
54592 else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
55593 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
56594
57
- bytesize = roundup(nvm_param.num_bits, BITS_PER_BYTE) / BITS_PER_BYTE;
58
- if (nvm_param.num_bits == 1)
59
- buf = &val->vbool;
60
-
61
- data_addr = dma_zalloc_coherent(&bp->pdev->dev, bytesize,
62
- &data_dma_addr, GFP_KERNEL);
63
- if (!data_addr)
595
+ data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data),
596
+ &data_dma_addr, GFP_KERNEL);
597
+ if (!data)
64598 return -ENOMEM;
65599
66600 req->dest_data_addr = cpu_to_le64(data_dma_addr);
67
- req->data_len = cpu_to_le16(nvm_param.num_bits);
601
+ req->data_len = cpu_to_le16(nvm_param.nvm_num_bits);
68602 req->option_num = cpu_to_le16(nvm_param.offset);
69603 req->index_0 = cpu_to_le16(idx);
70604 if (idx)
71605 req->dimensions = cpu_to_le16(1);
72606
73
- if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE))
74
- memcpy(data_addr, buf, bytesize);
607
+ if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
608
+ bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits,
609
+ nvm_param.dl_num_bytes);
610
+ rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
611
+ } else {
612
+ rc = hwrm_send_message_silent(bp, msg, msg_len,
613
+ HWRM_CMD_TIMEOUT);
614
+ if (!rc) {
615
+ bnxt_copy_from_nvm_data(val, data,
616
+ nvm_param.nvm_num_bits,
617
+ nvm_param.dl_num_bytes);
618
+ } else {
619
+ struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
75620
76
- rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
77
- if (!rc && req->req_type == cpu_to_le16(HWRM_NVM_GET_VARIABLE))
78
- memcpy(buf, data_addr, bytesize);
79
-
80
- dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr);
81
- if (rc == HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED) {
82
- netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
83
- return -EACCES;
84
- } else if (rc) {
85
- return -EIO;
621
+ if (resp->cmd_err ==
622
+ NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
623
+ rc = -EOPNOTSUPP;
624
+ }
86625 }
87
- return 0;
626
+ dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
627
+ if (rc == -EACCES)
628
+ netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
629
+ return rc;
88630 }
89631
90632 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
....@@ -92,9 +634,15 @@
92634 {
93635 struct hwrm_nvm_get_variable_input req = {0};
94636 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
637
+ int rc;
95638
96639 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
97
- return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
640
+ rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
641
+ if (!rc)
642
+ if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
643
+ ctx->val.vbool = !ctx->val.vbool;
644
+
645
+ return rc;
98646 }
99647
100648 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
....@@ -104,7 +652,31 @@
104652 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
105653
106654 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
655
+
656
+ if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
657
+ ctx->val.vbool = !ctx->val.vbool;
658
+
107659 return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
660
+}
661
+
662
+static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
663
+ union devlink_param_value val,
664
+ struct netlink_ext_ack *extack)
665
+{
666
+ int max_val = -1;
667
+
668
+ if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
669
+ max_val = BNXT_MSIX_VEC_MAX;
670
+
671
+ if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
672
+ max_val = BNXT_MSIX_VEC_MIN_MAX;
673
+
674
+ if (val.vu32 > max_val) {
675
+ NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
676
+ return -EINVAL;
677
+ }
678
+
679
+ return 0;
108680 }
109681
110682 static const struct devlink_param bnxt_dl_params[] = {
....@@ -112,21 +684,78 @@
112684 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
113685 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
114686 NULL),
687
+ DEVLINK_PARAM_GENERIC(IGNORE_ARI,
688
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
689
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
690
+ NULL),
691
+ DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
692
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
693
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
694
+ bnxt_dl_msix_validate),
695
+ DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
696
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
697
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
698
+ bnxt_dl_msix_validate),
699
+ DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
700
+ "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
701
+ BIT(DEVLINK_PARAM_CMODE_PERMANENT),
702
+ bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
703
+ NULL),
115704 };
705
+
706
+static const struct devlink_param bnxt_dl_port_params[] = {
707
+};
708
+
709
+static int bnxt_dl_params_register(struct bnxt *bp)
710
+{
711
+ int rc;
712
+
713
+ if (bp->hwrm_spec_code < 0x10600)
714
+ return 0;
715
+
716
+ rc = devlink_params_register(bp->dl, bnxt_dl_params,
717
+ ARRAY_SIZE(bnxt_dl_params));
718
+ if (rc) {
719
+ netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n",
720
+ rc);
721
+ return rc;
722
+ }
723
+ rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
724
+ ARRAY_SIZE(bnxt_dl_port_params));
725
+ if (rc) {
726
+ netdev_err(bp->dev, "devlink_port_params_register failed\n");
727
+ devlink_params_unregister(bp->dl, bnxt_dl_params,
728
+ ARRAY_SIZE(bnxt_dl_params));
729
+ return rc;
730
+ }
731
+ devlink_params_publish(bp->dl);
732
+
733
+ return 0;
734
+}
735
+
736
+static void bnxt_dl_params_unregister(struct bnxt *bp)
737
+{
738
+ if (bp->hwrm_spec_code < 0x10600)
739
+ return;
740
+
741
+ devlink_params_unregister(bp->dl, bnxt_dl_params,
742
+ ARRAY_SIZE(bnxt_dl_params));
743
+ devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
744
+ ARRAY_SIZE(bnxt_dl_port_params));
745
+}
116746
117747 int bnxt_dl_register(struct bnxt *bp)
118748 {
749
+ struct devlink_port_attrs attrs = {};
119750 struct devlink *dl;
120751 int rc;
121752
122
- if (bp->hwrm_spec_code < 0x10600) {
123
- netdev_warn(bp->dev, "Firmware does not support NVM params");
124
- return -ENOTSUPP;
125
- }
126
-
127
- dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
753
+ if (BNXT_PF(bp))
754
+ dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
755
+ else
756
+ dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
128757 if (!dl) {
129
- netdev_warn(bp->dev, "devlink_alloc failed");
758
+ netdev_warn(bp->dev, "devlink_alloc failed\n");
130759 return -ENOMEM;
131760 }
132761
....@@ -139,20 +768,32 @@
139768
140769 rc = devlink_register(dl, &bp->pdev->dev);
141770 if (rc) {
142
- netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
771
+ netdev_warn(bp->dev, "devlink_register failed. rc=%d\n", rc);
143772 goto err_dl_free;
144773 }
145774
146
- rc = devlink_params_register(dl, bnxt_dl_params,
147
- ARRAY_SIZE(bnxt_dl_params));
775
+ if (!BNXT_PF(bp))
776
+ return 0;
777
+
778
+ attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
779
+ attrs.phys.port_number = bp->pf.port_id;
780
+ memcpy(attrs.switch_id.id, bp->dsn, sizeof(bp->dsn));
781
+ attrs.switch_id.id_len = sizeof(bp->dsn);
782
+ devlink_port_attrs_set(&bp->dl_port, &attrs);
783
+ rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
148784 if (rc) {
149
- netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
150
- rc);
785
+ netdev_err(bp->dev, "devlink_port_register failed\n");
151786 goto err_dl_unreg;
152787 }
153788
789
+ rc = bnxt_dl_params_register(bp);
790
+ if (rc)
791
+ goto err_dl_port_unreg;
792
+
154793 return 0;
155794
795
+err_dl_port_unreg:
796
+ devlink_port_unregister(&bp->dl_port);
156797 err_dl_unreg:
157798 devlink_unregister(dl);
158799 err_dl_free:
....@@ -168,8 +809,10 @@
168809 if (!dl)
169810 return;
170811
171
- devlink_params_unregister(dl, bnxt_dl_params,
172
- ARRAY_SIZE(bnxt_dl_params));
812
+ if (BNXT_PF(bp)) {
813
+ bnxt_dl_params_unregister(bp);
814
+ devlink_port_unregister(&bp->dl_port);
815
+ }
173816 devlink_unregister(dl);
174817 devlink_free(dl);
175818 }