bnxt_en: implement devlink dev reload driver_reinit
[linux-block.git] / drivers / net / ethernet / broadcom / bnxt / bnxt_devlink.c
CommitLineData
3c467bf3
SL
1/* Broadcom NetXtreme-C/E network driver.
2 *
3 * Copyright (c) 2017 Broadcom Limited
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 */
9
10#include <linux/pci.h>
11#include <linux/netdevice.h>
477edb78 12#include <net/devlink.h>
3c467bf3
SL
13#include "bnxt_hsi.h"
14#include "bnxt.h"
3c8c20db 15#include "bnxt_hwrm.h"
3c467bf3
SL
16#include "bnxt_vfr.h"
17#include "bnxt_devlink.h"
d168f328 18#include "bnxt_ethtool.h"
228ea8c1
EP
19#include "bnxt_ulp.h"
20#include "bnxt_ptp.h"
d168f328
VV
21
22static int
bc75c054
JK
23bnxt_dl_flash_update(struct devlink *dl,
24 struct devlink_flash_update_params *params,
25 struct netlink_ext_ack *extack)
d168f328
VV
26{
27 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
8159cbe3 28 int rc;
d168f328 29
d168f328
VV
30 if (!BNXT_PF(bp)) {
31 NL_SET_ERR_MSG_MOD(extack,
32 "flash update not supported from a VF");
33 return -EPERM;
34 }
35
22ec3d23 36 devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0);
b44cfd4f 37 rc = bnxt_flash_package_from_fw_obj(bp->dev, params->fw, 0);
8159cbe3 38 if (!rc)
22ec3d23 39 devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0);
8159cbe3 40 else
22ec3d23 41 devlink_flash_update_status_notify(dl, "Flashing failed", NULL, 0, 0);
8159cbe3 42 return rc;
d168f328 43}
3c467bf3 44
6763c779 45static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
e7a98105
JP
46 struct devlink_fmsg *fmsg,
47 struct netlink_ext_ack *extack)
6763c779
VV
48{
49 struct bnxt *bp = devlink_health_reporter_priv(reporter);
fe1b8535 50 u32 val;
6763c779
VV
51 int rc;
52
0797c10d 53 if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
6763c779
VV
54 return 0;
55
56 val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
6763c779 57
fe1b8535 58 if (BNXT_FW_IS_BOOTING(val)) {
f255ed1c
VV
59 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
60 "Not yet completed initialization");
6763c779
VV
61 if (rc)
62 return rc;
fe1b8535 63 } else if (BNXT_FW_IS_ERR(val)) {
f255ed1c
VV
64 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
65 "Encountered fatal error and cannot recover");
6763c779
VV
66 if (rc)
67 return rc;
68 }
69
70 if (val >> 16) {
f255ed1c 71 rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16);
6763c779
VV
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
84static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
85 .name = "fw",
86 .diagnose = bnxt_fw_reporter_diagnose,
87};
88
657a33c8 89static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
e7a98105
JP
90 void *priv_ctx,
91 struct netlink_ext_ack *extack)
657a33c8
VV
92{
93 struct bnxt *bp = devlink_health_reporter_priv(reporter);
94
95 if (!priv_ctx)
96 return -EOPNOTSUPP;
97
98 bnxt_fw_reset(bp);
737d7a6c 99 return -EINPROGRESS;
657a33c8
VV
100}
101
102static const
103struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
104 .name = "fw_reset",
105 .recover = bnxt_fw_reset_recover,
106};
107
acfb50e4 108static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter,
e7a98105
JP
109 void *priv_ctx,
110 struct netlink_ext_ack *extack)
acfb50e4
VV
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
e4e38237 119 bp->fw_health->fatal = true;
acfb50e4
VV
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
737d7a6c 126 return -EINPROGRESS;
acfb50e4
VV
127}
128
129static const
130struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = {
131 .name = "fw_fatal",
132 .recover = bnxt_fw_fatal_recover,
133};
134
937f188c 135void bnxt_dl_fw_reporters_create(struct bnxt *bp)
6763c779
VV
136{
137 struct bnxt_fw_health *health = bp->fw_health;
138
e624c70e 139 if (!health)
6763c779
VV
140 return;
141
937f188c
VV
142 if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
143 goto err_recovery;
657a33c8
VV
144
145 health->fw_reset_reporter =
146 devlink_health_reporter_create(bp->dl,
147 &bnxt_dl_fw_reset_reporter_ops,
ba7d16c7 148 0, bp);
657a33c8
VV
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;
937f188c 153 bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
657a33c8 154 }
acfb50e4 155
937f188c
VV
156err_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,
ba7d16c7 164 0, bp);
937f188c
VV
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
acfb50e4
VV
177 health->fw_fatal_reporter =
178 devlink_health_reporter_create(bp->dl,
179 &bnxt_dl_fw_fatal_reporter_ops,
ba7d16c7 180 0, bp);
acfb50e4
VV
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;
937f188c 185 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
acfb50e4 186 }
6763c779
VV
187}
188
937f188c 189void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
6763c779
VV
190{
191 struct bnxt_fw_health *health = bp->fw_health;
192
e624c70e 193 if (!health)
6763c779
VV
194 return;
195
937f188c
VV
196 if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
197 health->fw_reset_reporter) {
657a33c8 198 devlink_health_reporter_destroy(health->fw_reset_reporter);
937f188c
VV
199 health->fw_reset_reporter = NULL;
200 }
acfb50e4 201
937f188c
VV
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) {
acfb50e4 211 devlink_health_reporter_destroy(health->fw_fatal_reporter);
937f188c
VV
212 health->fw_fatal_reporter = NULL;
213 }
657a33c8
VV
214}
215
216void 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
657a33c8
VV
221 fw_reporter_ctx.sp_event = event;
222 switch (event) {
223 case BNXT_FW_RESET_NOTIFY_SP_EVENT:
acfb50e4
VV
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 }
657a33c8
VV
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;
acfb50e4
VV
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;
657a33c8 249 }
6763c779
VV
250}
251
e4e38237
VV
252void 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
737d7a6c
VG
272void 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
9599e036
VV
282static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
283 struct netlink_ext_ack *extack);
284
228ea8c1
EP
285static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
286 enum devlink_reload_action action,
287 enum devlink_reload_limit limit,
288 struct netlink_ext_ack *extack)
289{
290 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
291 int rc = 0;
292
293 switch (action) {
294 case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: {
295 if (BNXT_PF(bp) && bp->pf.active_vfs) {
296 NL_SET_ERR_MSG_MOD(extack,
297 "reload is unsupported when VFs are allocated\n");
298 return -EOPNOTSUPP;
299 }
300 rtnl_lock();
301 if (bp->dev->reg_state == NETREG_UNREGISTERED) {
302 rtnl_unlock();
303 return -ENODEV;
304 }
305 bnxt_ulp_stop(bp);
306 if (netif_running(bp->dev)) {
307 rc = bnxt_close_nic(bp, true, true);
308 if (rc) {
309 NL_SET_ERR_MSG_MOD(extack, "Failed to close");
310 dev_close(bp->dev);
311 rtnl_unlock();
312 break;
313 }
314 }
315 bnxt_vf_reps_free(bp);
316 rc = bnxt_hwrm_func_drv_unrgtr(bp);
317 if (rc) {
318 NL_SET_ERR_MSG_MOD(extack, "Failed to deregister");
319 if (netif_running(bp->dev))
320 dev_close(bp->dev);
321 rtnl_unlock();
322 break;
323 }
324 bnxt_cancel_reservations(bp, false);
325 bnxt_free_ctx_mem(bp);
326 kfree(bp->ctx);
327 bp->ctx = NULL;
328 break;
329 }
330 default:
331 rc = -EOPNOTSUPP;
332 }
333
334 return rc;
335}
336
337static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action action,
338 enum devlink_reload_limit limit, u32 *actions_performed,
339 struct netlink_ext_ack *extack)
340{
341 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
342 int rc = 0;
343
344 *actions_performed = 0;
345 switch (action) {
346 case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: {
347 bnxt_fw_init_one(bp);
348 bnxt_vf_reps_alloc(bp);
349 if (netif_running(bp->dev))
350 rc = bnxt_open_nic(bp, true, true);
351 bnxt_ulp_start(bp, rc);
352 if (!rc) {
353 bnxt_reenable_sriov(bp);
354 bnxt_ptp_reapply_pps(bp);
355 }
356 break;
357 }
358 default:
359 return -EOPNOTSUPP;
360 }
361
362 if (!rc) {
363 bnxt_print_device_info(bp);
364 if (netif_running(bp->dev)) {
365 mutex_lock(&bp->link_lock);
366 bnxt_report_link(bp);
367 mutex_unlock(&bp->link_lock);
368 }
369 *actions_performed |= BIT(action);
370 } else if (netif_running(bp->dev)) {
371 dev_close(bp->dev);
372 }
373 rtnl_unlock();
374 return rc;
375}
376
3c467bf3
SL
377static const struct devlink_ops bnxt_dl_ops = {
378#ifdef CONFIG_BNXT_SRIOV
379 .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
380 .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
381#endif /* CONFIG_BNXT_SRIOV */
9599e036 382 .info_get = bnxt_dl_info_get,
d168f328 383 .flash_update = bnxt_dl_flash_update,
228ea8c1
EP
384 .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT),
385 .reload_down = bnxt_dl_reload_down,
386 .reload_up = bnxt_dl_reload_up,
3c467bf3
SL
387};
388
7e334fc8
VV
389static const struct devlink_ops bnxt_vf_dl_ops;
390
2dc0865e
VV
391enum bnxt_dl_param_id {
392 BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
393 BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
394};
395
6354b95e
VV
396static const struct bnxt_dl_nvm_param nvm_params[] = {
397 {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
c329230c 398 BNXT_NVM_SHARED_CFG, 1, 1},
7d859234 399 {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
c329230c 400 BNXT_NVM_SHARED_CFG, 1, 1},
f399e849 401 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
c329230c 402 NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4},
f399e849 403 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
c329230c 404 NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4},
2dc0865e 405 {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
c329230c 406 BNXT_NVM_SHARED_CFG, 1, 1},
6354b95e
VV
407};
408
83a46a82
MC
409union bnxt_nvm_data {
410 u8 val8;
411 __le32 val32;
412};
413
414static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst,
415 union devlink_param_value *src,
416 int nvm_num_bits, int dl_num_bytes)
417{
418 u32 val32 = 0;
419
420 if (nvm_num_bits == 1) {
421 dst->val8 = src->vbool;
422 return;
423 }
424 if (dl_num_bytes == 4)
425 val32 = src->vu32;
426 else if (dl_num_bytes == 2)
427 val32 = (u32)src->vu16;
428 else if (dl_num_bytes == 1)
429 val32 = (u32)src->vu8;
430 dst->val32 = cpu_to_le32(val32);
431}
432
433static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
434 union bnxt_nvm_data *src,
435 int nvm_num_bits, int dl_num_bytes)
436{
437 u32 val32;
438
439 if (nvm_num_bits == 1) {
440 dst->vbool = src->val8;
441 return;
442 }
443 val32 = le32_to_cpu(src->val32);
444 if (dl_num_bytes == 4)
445 dst->vu32 = val32;
446 else if (dl_num_bytes == 2)
447 dst->vu16 = (u16)val32;
448 else if (dl_num_bytes == 1)
449 dst->vu8 = (u8)val32;
450}
451
beb55fcf 452static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver)
9599e036 453{
bbf33d1d 454 struct hwrm_nvm_get_variable_input *req;
beb55fcf
EP
455 u16 bytes = BNXT_NVM_CFG_VER_BYTES;
456 u16 bits = BNXT_NVM_CFG_VER_BITS;
457 union devlink_param_value ver;
9599e036
VV
458 union bnxt_nvm_data *data;
459 dma_addr_t data_dma_addr;
beb55fcf
EP
460 int rc, i = 2;
461 u16 dim = 1;
9599e036 462
bbf33d1d
EP
463 rc = hwrm_req_init(bp, req, HWRM_NVM_GET_VARIABLE);
464 if (rc)
465 return rc;
466
467 data = hwrm_req_dma_slice(bp, req, sizeof(*data), &data_dma_addr);
468 if (!data) {
469 rc = -ENOMEM;
470 goto exit;
471 }
9599e036 472
beb55fcf
EP
473 /* earlier devices present as an array of raw bytes */
474 if (!BNXT_CHIP_P5(bp)) {
475 dim = 0;
476 i = 0;
477 bits *= 3; /* array of 3 version components */
478 bytes *= 4; /* copy whole word */
479 }
480
bbf33d1d
EP
481 hwrm_req_hold(bp, req);
482 req->dest_data_addr = cpu_to_le64(data_dma_addr);
beb55fcf 483 req->data_len = cpu_to_le16(bits);
bbf33d1d 484 req->option_num = cpu_to_le16(NVM_OFF_NVM_CFG_VER);
beb55fcf 485 req->dimensions = cpu_to_le16(dim);
9599e036 486
beb55fcf
EP
487 while (i >= 0) {
488 req->index_0 = cpu_to_le16(i--);
489 rc = hwrm_req_send_silent(bp, req);
490 if (rc)
491 goto exit;
492 bnxt_copy_from_nvm_data(&ver, data, bits, bytes);
493
494 if (BNXT_CHIP_P5(bp)) {
495 *nvm_cfg_ver <<= 8;
496 *nvm_cfg_ver |= ver.vu8;
497 } else {
498 *nvm_cfg_ver = ver.vu32;
499 }
500 }
9599e036 501
bbf33d1d
EP
502exit:
503 hwrm_req_drop(bp, req);
9599e036
VV
504 return rc;
505}
506
7154917a
VV
507static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req,
508 enum bnxt_dl_version_type type, const char *key,
509 char *buf)
510{
511 if (!strlen(buf))
512 return 0;
513
514 if ((bp->flags & BNXT_FLAG_CHIP_P5) &&
515 (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) ||
516 !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE)))
517 return 0;
518
519 switch (type) {
520 case BNXT_VERSION_FIXED:
521 return devlink_info_version_fixed_put(req, key, buf);
522 case BNXT_VERSION_RUNNING:
523 return devlink_info_version_running_put(req, key, buf);
524 case BNXT_VERSION_STORED:
525 return devlink_info_version_stored_put(req, key, buf);
526 }
527 return 0;
528}
529
530#define HWRM_FW_VER_STR_LEN 16
531
9599e036
VV
532static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
533 struct netlink_ext_ack *extack)
534{
1388875b 535 struct hwrm_nvm_get_dev_info_output nvm_dev_info;
9599e036 536 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
9599e036
VV
537 struct hwrm_ver_get_output *ver_resp;
538 char mgmt_ver[FW_VER_STR_LEN];
539 char roce_ver[FW_VER_STR_LEN];
7154917a 540 char ncsi_ver[FW_VER_STR_LEN];
9599e036 541 char buf[32];
beb55fcf 542 u32 ver = 0;
9599e036
VV
543 int rc;
544
545 rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME);
546 if (rc)
547 return rc;
548
7154917a
VV
549 if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) {
550 sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
551 bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4],
552 bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]);
553 rc = devlink_info_serial_number_put(req, buf);
56d69c78
VV
554 if (rc)
555 return rc;
556 }
557
9bf88b9f
VV
558 if (strlen(bp->board_serialno)) {
559 rc = devlink_info_board_serial_number_put(req, bp->board_serialno);
560 if (rc)
561 return rc;
562 }
563
7154917a
VV
564 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED,
565 DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
566 bp->board_partno);
567 if (rc)
568 return rc;
569
9599e036 570 sprintf(buf, "%X", bp->chip_num);
7154917a
VV
571 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED,
572 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf);
9599e036
VV
573 if (rc)
574 return rc;
575
576 ver_resp = &bp->ver_resp;
6fdab8a3 577 sprintf(buf, "%c%d", 'A' + ver_resp->chip_rev, ver_resp->chip_metal);
7154917a
VV
578 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED,
579 DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf);
9599e036
VV
580 if (rc)
581 return rc;
582
1388875b
VV
583 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
584 DEVLINK_INFO_VERSION_GENERIC_FW_PSID,
585 bp->nvm_cfg_ver);
586 if (rc)
587 return rc;
588
7154917a
VV
589 buf[0] = 0;
590 strncat(buf, ver_resp->active_pkg_name, HWRM_FW_VER_STR_LEN);
591 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
592 DEVLINK_INFO_VERSION_GENERIC_FW, buf);
593 if (rc)
594 return rc;
9599e036 595
beb55fcf 596 if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &ver)) {
1656db67
EP
597 sprintf(buf, "%d.%d.%d", (ver >> 16) & 0xff, (ver >> 8) & 0xff,
598 ver & 0xff);
1388875b 599 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
7154917a
VV
600 DEVLINK_INFO_VERSION_GENERIC_FW_PSID,
601 buf);
9599e036
VV
602 if (rc)
603 return rc;
604 }
605
606 if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) {
7154917a 607 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
9599e036
VV
608 ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor,
609 ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch);
610
7154917a 611 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
9599e036
VV
612 ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor,
613 ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch);
614
615 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
616 ver_resp->roce_fw_major, ver_resp->roce_fw_minor,
617 ver_resp->roce_fw_build, ver_resp->roce_fw_patch);
618 } else {
7154917a 619 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
9599e036
VV
620 ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b,
621 ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b);
622
7154917a 623 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
9599e036
VV
624 ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b,
625 ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b);
626
627 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
628 ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b,
629 ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b);
630 }
7154917a
VV
631 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
632 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
9599e036
VV
633 if (rc)
634 return rc;
635
7154917a
VV
636 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
637 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
638 bp->hwrm_ver_supp);
b7a444f0
VV
639 if (rc)
640 return rc;
641
7154917a
VV
642 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
643 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver);
644 if (rc)
645 return rc;
9599e036 646
1388875b
VV
647 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING,
648 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
649 if (rc)
650 return rc;
651
652 rc = bnxt_hwrm_nvm_get_dev_info(bp, &nvm_dev_info);
653 if (rc ||
654 !(nvm_dev_info.flags & NVM_GET_DEV_INFO_RESP_FLAGS_FW_VER_VALID))
655 return 0;
656
657 buf[0] = 0;
658 strncat(buf, nvm_dev_info.pkg_name, HWRM_FW_VER_STR_LEN);
659 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
660 DEVLINK_INFO_VERSION_GENERIC_FW, buf);
661 if (rc)
662 return rc;
663
664 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
665 nvm_dev_info.hwrm_fw_major, nvm_dev_info.hwrm_fw_minor,
666 nvm_dev_info.hwrm_fw_build, nvm_dev_info.hwrm_fw_patch);
667 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
668 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
669 if (rc)
670 return rc;
671
672 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
673 nvm_dev_info.mgmt_fw_major, nvm_dev_info.mgmt_fw_minor,
674 nvm_dev_info.mgmt_fw_build, nvm_dev_info.mgmt_fw_patch);
675 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
676 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver);
677 if (rc)
678 return rc;
679
680 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
681 nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor,
682 nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch);
683 return bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED,
7154917a 684 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
9599e036
VV
685}
686
6354b95e 687static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
bbf33d1d 688 union devlink_param_value *val)
6354b95e 689{
6fc92c33 690 struct hwrm_nvm_get_variable_input *req = msg;
6354b95e 691 struct bnxt_dl_nvm_param nvm_param;
bbf33d1d 692 struct hwrm_err_output *resp;
83a46a82 693 union bnxt_nvm_data *data;
6354b95e 694 dma_addr_t data_dma_addr;
c329230c 695 int idx = 0, rc, i;
6354b95e
VV
696
697 /* Get/Set NVM CFG parameter is supported only on PFs */
bbf33d1d
EP
698 if (BNXT_VF(bp)) {
699 hwrm_req_drop(bp, req);
6354b95e 700 return -EPERM;
bbf33d1d 701 }
6354b95e
VV
702
703 for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
704 if (nvm_params[i].id == param_id) {
705 nvm_param = nvm_params[i];
706 break;
707 }
708 }
709
bbf33d1d
EP
710 if (i == ARRAY_SIZE(nvm_params)) {
711 hwrm_req_drop(bp, req);
65fac4fe 712 return -EOPNOTSUPP;
bbf33d1d 713 }
65fac4fe 714
6354b95e
VV
715 if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
716 idx = bp->pf.port_id;
717 else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
718 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
719
bbf33d1d
EP
720 data = hwrm_req_dma_slice(bp, req, sizeof(*data), &data_dma_addr);
721
722 if (!data) {
723 hwrm_req_drop(bp, req);
6354b95e 724 return -ENOMEM;
bbf33d1d 725 }
6354b95e 726
6fc92c33 727 req->dest_data_addr = cpu_to_le64(data_dma_addr);
c329230c 728 req->data_len = cpu_to_le16(nvm_param.nvm_num_bits);
6354b95e
VV
729 req->option_num = cpu_to_le16(nvm_param.offset);
730 req->index_0 = cpu_to_le16(idx);
731 if (idx)
732 req->dimensions = cpu_to_le16(1);
733
bbf33d1d 734 resp = hwrm_req_hold(bp, req);
b703ba75 735 if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
83a46a82
MC
736 bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits,
737 nvm_param.dl_num_bytes);
bbf33d1d 738 rc = hwrm_req_send(bp, msg);
b703ba75 739 } else {
bbf33d1d 740 rc = hwrm_req_send_silent(bp, msg);
05069dd4 741 if (!rc) {
83a46a82
MC
742 bnxt_copy_from_nvm_data(val, data,
743 nvm_param.nvm_num_bits,
744 nvm_param.dl_num_bytes);
05069dd4 745 } else {
05069dd4
VV
746 if (resp->cmd_err ==
747 NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
748 rc = -EOPNOTSUPP;
749 }
b703ba75 750 }
bbf33d1d 751 hwrm_req_drop(bp, req);
d4f1420d 752 if (rc == -EACCES)
3a1d52a5 753 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
d4f1420d 754 return rc;
6354b95e
VV
755}
756
757static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
758 struct devlink_param_gset_ctx *ctx)
759{
6354b95e 760 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
bbf33d1d 761 struct hwrm_nvm_get_variable_input *req;
2dc0865e 762 int rc;
6354b95e 763
bbf33d1d
EP
764 rc = hwrm_req_init(bp, req, HWRM_NVM_GET_VARIABLE);
765 if (rc)
766 return rc;
767
768 rc = bnxt_hwrm_nvm_req(bp, id, req, &ctx->val);
769 if (!rc && id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
770 ctx->val.vbool = !ctx->val.vbool;
2dc0865e
VV
771
772 return rc;
6354b95e
VV
773}
774
775static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
776 struct devlink_param_gset_ctx *ctx)
777{
6354b95e 778 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
bbf33d1d
EP
779 struct hwrm_nvm_set_variable_input *req;
780 int rc;
6354b95e 781
bbf33d1d
EP
782 rc = hwrm_req_init(bp, req, HWRM_NVM_SET_VARIABLE);
783 if (rc)
784 return rc;
2dc0865e
VV
785
786 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
787 ctx->val.vbool = !ctx->val.vbool;
788
bbf33d1d 789 return bnxt_hwrm_nvm_req(bp, id, req, &ctx->val);
6354b95e
VV
790}
791
f399e849
VV
792static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
793 union devlink_param_value val,
794 struct netlink_ext_ack *extack)
795{
5fc7c12f 796 int max_val = -1;
f399e849
VV
797
798 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
799 max_val = BNXT_MSIX_VEC_MAX;
800
801 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
802 max_val = BNXT_MSIX_VEC_MIN_MAX;
803
5fc7c12f 804 if (val.vu32 > max_val) {
f399e849
VV
805 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
806 return -EINVAL;
807 }
808
809 return 0;
810}
811
6354b95e
VV
812static const struct devlink_param bnxt_dl_params[] = {
813 DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
814 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
815 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
816 NULL),
7d859234
VV
817 DEVLINK_PARAM_GENERIC(IGNORE_ARI,
818 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
819 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
820 NULL),
f399e849
VV
821 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
822 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
823 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
824 bnxt_dl_msix_validate),
825 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
826 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
827 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
828 bnxt_dl_msix_validate),
2dc0865e
VV
829 DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
830 "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
831 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
832 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
833 NULL),
6354b95e
VV
834};
835
d6292ade
VV
836static int bnxt_dl_params_register(struct bnxt *bp)
837{
838 int rc;
839
002870eb
VV
840 if (bp->hwrm_spec_code < 0x10600)
841 return 0;
842
d6292ade
VV
843 rc = devlink_params_register(bp->dl, bnxt_dl_params,
844 ARRAY_SIZE(bnxt_dl_params));
5df290e7 845 if (rc)
9a005c38 846 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n",
d6292ade 847 rc);
5df290e7 848 return rc;
d6292ade
VV
849}
850
851static void bnxt_dl_params_unregister(struct bnxt *bp)
852{
002870eb
VV
853 if (bp->hwrm_spec_code < 0x10600)
854 return;
855
d6292ade
VV
856 devlink_params_unregister(bp->dl, bnxt_dl_params,
857 ARRAY_SIZE(bnxt_dl_params));
d6292ade
VV
858}
859
3c467bf3
SL
860int bnxt_dl_register(struct bnxt *bp)
861{
919d13a7 862 const struct devlink_ops *devlink_ops;
71ad8d55 863 struct devlink_port_attrs attrs = {};
e624c70e 864 struct bnxt_dl *bp_dl;
3c467bf3
SL
865 struct devlink *dl;
866 int rc;
867
7e334fc8 868 if (BNXT_PF(bp))
919d13a7 869 devlink_ops = &bnxt_dl_ops;
7e334fc8 870 else
919d13a7
LR
871 devlink_ops = &bnxt_vf_dl_ops;
872
873 dl = devlink_alloc(devlink_ops, sizeof(struct bnxt_dl), &bp->pdev->dev);
3c467bf3 874 if (!dl) {
9a005c38 875 netdev_warn(bp->dev, "devlink_alloc failed\n");
3c467bf3
SL
876 return -ENOMEM;
877 }
878
e624c70e
LR
879 bp->dl = dl;
880 bp_dl = devlink_priv(dl);
881 bp_dl->bp = bp;
6354b95e
VV
882
883 /* Add switchdev eswitch mode setting, if SRIOV supported */
884 if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
885 bp->hwrm_spec_code > 0x10803)
886 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
887
7e334fc8 888 if (!BNXT_PF(bp))
5df290e7 889 goto out;
7e334fc8 890
71ad8d55
DR
891 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
892 attrs.phys.port_number = bp->pf.port_id;
893 memcpy(attrs.switch_id.id, bp->dsn, sizeof(bp->dsn));
894 attrs.switch_id.id_len = sizeof(bp->dsn);
895 devlink_port_attrs_set(&bp->dl_port, &attrs);
782a624d
VV
896 rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
897 if (rc) {
9a005c38 898 netdev_err(bp->dev, "devlink_port_register failed\n");
db4278c5 899 goto err_dl_free;
782a624d 900 }
782a624d 901
d6292ade
VV
902 rc = bnxt_dl_params_register(bp);
903 if (rc)
782a624d 904 goto err_dl_port_unreg;
7c62cfb8 905
5df290e7
LR
906out:
907 devlink_register(dl);
3c467bf3 908 return 0;
6354b95e 909
782a624d
VV
910err_dl_port_unreg:
911 devlink_port_unregister(&bp->dl_port);
6354b95e 912err_dl_free:
6354b95e
VV
913 devlink_free(dl);
914 return rc;
3c467bf3
SL
915}
916
917void bnxt_dl_unregister(struct bnxt *bp)
918{
919 struct devlink *dl = bp->dl;
920
5df290e7 921 devlink_unregister(dl);
7e334fc8 922 if (BNXT_PF(bp)) {
d6292ade 923 bnxt_dl_params_unregister(bp);
7e334fc8 924 devlink_port_unregister(&bp->dl_port);
7e334fc8 925 }
3c467bf3
SL
926 devlink_free(dl);
927}