1 /* Broadcom NetXtreme-C/E network driver.
3 * Copyright (c) 2017 Broadcom Limited
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.
10 #include <linux/pci.h>
11 #include <linux/netdevice.h>
12 #include <net/devlink.h>
16 #include "bnxt_devlink.h"
17 #include "bnxt_ethtool.h"
20 bnxt_dl_flash_update(struct devlink *dl, const char *filename,
21 const char *region, struct netlink_ext_ack *extack)
23 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
29 NL_SET_ERR_MSG_MOD(extack,
30 "flash update not supported from a VF");
34 return bnxt_flash_package_from_file(bp->dev, filename, 0);
37 static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
38 struct devlink_fmsg *fmsg,
39 struct netlink_ext_ack *extack)
41 struct bnxt *bp = devlink_health_reporter_priv(reporter);
42 u32 val, health_status;
45 if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
48 val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
49 health_status = val & 0xffff;
51 if (health_status < BNXT_FW_STATUS_HEALTHY) {
52 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
53 "Not yet completed initialization");
56 } else if (health_status > BNXT_FW_STATUS_HEALTHY) {
57 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
58 "Encountered fatal error and cannot recover");
64 rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16);
69 val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
70 rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val);
77 static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
79 .diagnose = bnxt_fw_reporter_diagnose,
82 static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
84 struct netlink_ext_ack *extack)
86 struct bnxt *bp = devlink_health_reporter_priv(reporter);
96 struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
98 .recover = bnxt_fw_reset_recover,
101 static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter,
103 struct netlink_ext_ack *extack)
105 struct bnxt *bp = devlink_health_reporter_priv(reporter);
106 struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
112 bp->fw_health->fatal = true;
113 event = fw_reporter_ctx->sp_event;
114 if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT)
116 else if (event == BNXT_FW_EXCEPTION_SP_EVENT)
117 bnxt_fw_exception(bp);
123 struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = {
125 .recover = bnxt_fw_fatal_recover,
128 void bnxt_dl_fw_reporters_create(struct bnxt *bp)
130 struct bnxt_fw_health *health = bp->fw_health;
132 if (!bp->dl || !health)
135 if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
138 health->fw_reset_reporter =
139 devlink_health_reporter_create(bp->dl,
140 &bnxt_dl_fw_reset_reporter_ops,
142 if (IS_ERR(health->fw_reset_reporter)) {
143 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
144 PTR_ERR(health->fw_reset_reporter));
145 health->fw_reset_reporter = NULL;
146 bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
150 if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
153 if (!health->fw_reporter) {
154 health->fw_reporter =
155 devlink_health_reporter_create(bp->dl,
156 &bnxt_dl_fw_reporter_ops,
158 if (IS_ERR(health->fw_reporter)) {
159 netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
160 PTR_ERR(health->fw_reporter));
161 health->fw_reporter = NULL;
162 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
167 if (health->fw_fatal_reporter)
170 health->fw_fatal_reporter =
171 devlink_health_reporter_create(bp->dl,
172 &bnxt_dl_fw_fatal_reporter_ops,
174 if (IS_ERR(health->fw_fatal_reporter)) {
175 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
176 PTR_ERR(health->fw_fatal_reporter));
177 health->fw_fatal_reporter = NULL;
178 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
182 void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
184 struct bnxt_fw_health *health = bp->fw_health;
186 if (!bp->dl || !health)
189 if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
190 health->fw_reset_reporter) {
191 devlink_health_reporter_destroy(health->fw_reset_reporter);
192 health->fw_reset_reporter = NULL;
195 if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all)
198 if (health->fw_reporter) {
199 devlink_health_reporter_destroy(health->fw_reporter);
200 health->fw_reporter = NULL;
203 if (health->fw_fatal_reporter) {
204 devlink_health_reporter_destroy(health->fw_fatal_reporter);
205 health->fw_fatal_reporter = NULL;
209 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
211 struct bnxt_fw_health *fw_health = bp->fw_health;
212 struct bnxt_fw_reporter_ctx fw_reporter_ctx;
214 fw_reporter_ctx.sp_event = event;
216 case BNXT_FW_RESET_NOTIFY_SP_EVENT:
217 if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) {
218 if (!fw_health->fw_fatal_reporter)
221 devlink_health_report(fw_health->fw_fatal_reporter,
222 "FW fatal async event received",
226 if (!fw_health->fw_reset_reporter)
229 devlink_health_report(fw_health->fw_reset_reporter,
230 "FW non-fatal reset event received",
234 case BNXT_FW_EXCEPTION_SP_EVENT:
235 if (!fw_health->fw_fatal_reporter)
238 devlink_health_report(fw_health->fw_fatal_reporter,
239 "FW fatal error reported",
245 void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy)
247 struct bnxt_fw_health *health = bp->fw_health;
251 state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
253 state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
256 devlink_health_reporter_state_update(health->fw_fatal_reporter,
259 devlink_health_reporter_state_update(health->fw_reset_reporter,
262 health->fatal = false;
265 static const struct devlink_ops bnxt_dl_ops = {
266 #ifdef CONFIG_BNXT_SRIOV
267 .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
268 .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
269 #endif /* CONFIG_BNXT_SRIOV */
270 .flash_update = bnxt_dl_flash_update,
273 static const struct devlink_ops bnxt_vf_dl_ops;
275 enum bnxt_dl_param_id {
276 BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
277 BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
280 static const struct bnxt_dl_nvm_param nvm_params[] = {
281 {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
282 BNXT_NVM_SHARED_CFG, 1, 1},
283 {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
284 BNXT_NVM_SHARED_CFG, 1, 1},
285 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
286 NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4},
287 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
288 NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4},
289 {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
290 BNXT_NVM_SHARED_CFG, 1, 1},
293 union bnxt_nvm_data {
298 static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst,
299 union devlink_param_value *src,
300 int nvm_num_bits, int dl_num_bytes)
304 if (nvm_num_bits == 1) {
305 dst->val8 = src->vbool;
308 if (dl_num_bytes == 4)
310 else if (dl_num_bytes == 2)
311 val32 = (u32)src->vu16;
312 else if (dl_num_bytes == 1)
313 val32 = (u32)src->vu8;
314 dst->val32 = cpu_to_le32(val32);
317 static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
318 union bnxt_nvm_data *src,
319 int nvm_num_bits, int dl_num_bytes)
323 if (nvm_num_bits == 1) {
324 dst->vbool = src->val8;
327 val32 = le32_to_cpu(src->val32);
328 if (dl_num_bytes == 4)
330 else if (dl_num_bytes == 2)
331 dst->vu16 = (u16)val32;
332 else if (dl_num_bytes == 1)
333 dst->vu8 = (u8)val32;
336 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
337 int msg_len, union devlink_param_value *val)
339 struct hwrm_nvm_get_variable_input *req = msg;
340 struct bnxt_dl_nvm_param nvm_param;
341 union bnxt_nvm_data *data;
342 dma_addr_t data_dma_addr;
345 /* Get/Set NVM CFG parameter is supported only on PFs */
349 for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
350 if (nvm_params[i].id == param_id) {
351 nvm_param = nvm_params[i];
356 if (i == ARRAY_SIZE(nvm_params))
359 if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
360 idx = bp->pf.port_id;
361 else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
362 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
364 data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data),
365 &data_dma_addr, GFP_KERNEL);
369 req->dest_data_addr = cpu_to_le64(data_dma_addr);
370 req->data_len = cpu_to_le16(nvm_param.nvm_num_bits);
371 req->option_num = cpu_to_le16(nvm_param.offset);
372 req->index_0 = cpu_to_le16(idx);
374 req->dimensions = cpu_to_le16(1);
376 if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
377 bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits,
378 nvm_param.dl_num_bytes);
379 rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
381 rc = hwrm_send_message_silent(bp, msg, msg_len,
384 bnxt_copy_from_nvm_data(val, data,
385 nvm_param.nvm_num_bits,
386 nvm_param.dl_num_bytes);
388 struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
391 NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
395 dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
397 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
401 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
402 struct devlink_param_gset_ctx *ctx)
404 struct hwrm_nvm_get_variable_input req = {0};
405 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
408 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
409 rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
411 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
412 ctx->val.vbool = !ctx->val.vbool;
417 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
418 struct devlink_param_gset_ctx *ctx)
420 struct hwrm_nvm_set_variable_input req = {0};
421 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
423 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
425 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
426 ctx->val.vbool = !ctx->val.vbool;
428 return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
431 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
432 union devlink_param_value val,
433 struct netlink_ext_ack *extack)
437 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
438 max_val = BNXT_MSIX_VEC_MAX;
440 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
441 max_val = BNXT_MSIX_VEC_MIN_MAX;
443 if (val.vu32 > max_val) {
444 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
451 static const struct devlink_param bnxt_dl_params[] = {
452 DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
453 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
454 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
456 DEVLINK_PARAM_GENERIC(IGNORE_ARI,
457 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
458 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
460 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
461 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
462 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
463 bnxt_dl_msix_validate),
464 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
465 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
466 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
467 bnxt_dl_msix_validate),
468 DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
469 "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
470 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
471 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
475 static const struct devlink_param bnxt_dl_port_params[] = {
478 int bnxt_dl_register(struct bnxt *bp)
483 if (bp->hwrm_spec_code < 0x10600) {
484 netdev_warn(bp->dev, "Firmware does not support NVM params");
489 dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
491 dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
493 netdev_warn(bp->dev, "devlink_alloc failed");
497 bnxt_link_bp_to_dl(bp, dl);
499 /* Add switchdev eswitch mode setting, if SRIOV supported */
500 if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
501 bp->hwrm_spec_code > 0x10803)
502 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
504 rc = devlink_register(dl, &bp->pdev->dev);
506 netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
513 rc = devlink_params_register(dl, bnxt_dl_params,
514 ARRAY_SIZE(bnxt_dl_params));
516 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
521 devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
522 bp->pf.port_id, false, 0,
523 bp->switch_id, sizeof(bp->switch_id));
524 rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
526 netdev_err(bp->dev, "devlink_port_register failed");
527 goto err_dl_param_unreg;
529 devlink_port_type_eth_set(&bp->dl_port, bp->dev);
531 rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
532 ARRAY_SIZE(bnxt_dl_port_params));
534 netdev_err(bp->dev, "devlink_port_params_register failed");
535 goto err_dl_port_unreg;
538 devlink_params_publish(dl);
543 devlink_port_unregister(&bp->dl_port);
545 devlink_params_unregister(dl, bnxt_dl_params,
546 ARRAY_SIZE(bnxt_dl_params));
548 devlink_unregister(dl);
550 bnxt_link_bp_to_dl(bp, NULL);
555 void bnxt_dl_unregister(struct bnxt *bp)
557 struct devlink *dl = bp->dl;
563 devlink_port_params_unregister(&bp->dl_port,
565 ARRAY_SIZE(bnxt_dl_port_params));
566 devlink_port_unregister(&bp->dl_port);
567 devlink_params_unregister(dl, bnxt_dl_params,
568 ARRAY_SIZE(bnxt_dl_params));
570 devlink_unregister(dl);