152306deeSIgor Russkikh // SPDX-License-Identifier: GPL-2.0-or-later 252306deeSIgor Russkikh /* Marvell/Qlogic FastLinQ NIC driver 352306deeSIgor Russkikh * 452306deeSIgor Russkikh * Copyright (C) 2020 Marvell International Ltd. 552306deeSIgor Russkikh */ 652306deeSIgor Russkikh 752306deeSIgor Russkikh #include <linux/kernel.h> 8755f982bSIgor Russkikh #include <linux/qed/qed_if.h> 952306deeSIgor Russkikh #include "qed.h" 1052306deeSIgor Russkikh #include "qed_devlink.h" 1152306deeSIgor Russkikh 1252306deeSIgor Russkikh enum qed_devlink_param_id { 1352306deeSIgor Russkikh QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 1452306deeSIgor Russkikh QED_DEVLINK_PARAM_ID_IWARP_CMT, 1552306deeSIgor Russkikh }; 1652306deeSIgor Russkikh 174f5a8db2SIgor Russkikh struct qed_fw_fatal_ctx { 184f5a8db2SIgor Russkikh enum qed_hw_err_type err_type; 194f5a8db2SIgor Russkikh }; 204f5a8db2SIgor Russkikh 214f5a8db2SIgor Russkikh int qed_report_fatal_error(struct devlink *devlink, enum qed_hw_err_type err_type) 224f5a8db2SIgor Russkikh { 234f5a8db2SIgor Russkikh struct qed_devlink *qdl = devlink_priv(devlink); 244f5a8db2SIgor Russkikh struct qed_fw_fatal_ctx fw_fatal_ctx = { 254f5a8db2SIgor Russkikh .err_type = err_type, 264f5a8db2SIgor Russkikh }; 274f5a8db2SIgor Russkikh 284f5a8db2SIgor Russkikh if (qdl->fw_reporter) 294f5a8db2SIgor Russkikh devlink_health_report(qdl->fw_reporter, 304f5a8db2SIgor Russkikh "Fatal error occurred", &fw_fatal_ctx); 314f5a8db2SIgor Russkikh 324f5a8db2SIgor Russkikh return 0; 334f5a8db2SIgor Russkikh } 344f5a8db2SIgor Russkikh 359524067bSIgor Russkikh static const struct devlink_health_reporter_ops qed_fw_fatal_reporter_ops = { 369524067bSIgor Russkikh .name = "fw_fatal", 379524067bSIgor Russkikh }; 389524067bSIgor Russkikh 399524067bSIgor Russkikh #define QED_REPORTER_FW_GRACEFUL_PERIOD 1200000 409524067bSIgor Russkikh 419524067bSIgor Russkikh void qed_fw_reporters_create(struct devlink *devlink) 429524067bSIgor Russkikh { 439524067bSIgor Russkikh struct qed_devlink *dl = devlink_priv(devlink); 449524067bSIgor Russkikh 459524067bSIgor Russkikh dl->fw_reporter = devlink_health_reporter_create(devlink, &qed_fw_fatal_reporter_ops, 469524067bSIgor Russkikh QED_REPORTER_FW_GRACEFUL_PERIOD, dl); 479524067bSIgor Russkikh if (IS_ERR(dl->fw_reporter)) { 489524067bSIgor Russkikh DP_NOTICE(dl->cdev, "Failed to create fw reporter, err = %ld\n", 499524067bSIgor Russkikh PTR_ERR(dl->fw_reporter)); 509524067bSIgor Russkikh dl->fw_reporter = NULL; 519524067bSIgor Russkikh } 529524067bSIgor Russkikh } 539524067bSIgor Russkikh 549524067bSIgor Russkikh void qed_fw_reporters_destroy(struct devlink *devlink) 559524067bSIgor Russkikh { 569524067bSIgor Russkikh struct qed_devlink *dl = devlink_priv(devlink); 579524067bSIgor Russkikh struct devlink_health_reporter *rep; 589524067bSIgor Russkikh 599524067bSIgor Russkikh rep = dl->fw_reporter; 609524067bSIgor Russkikh 619524067bSIgor Russkikh if (!IS_ERR_OR_NULL(rep)) 629524067bSIgor Russkikh devlink_health_reporter_destroy(rep); 639524067bSIgor Russkikh } 649524067bSIgor Russkikh 6552306deeSIgor Russkikh static int qed_dl_param_get(struct devlink *dl, u32 id, 6652306deeSIgor Russkikh struct devlink_param_gset_ctx *ctx) 6752306deeSIgor Russkikh { 68755f982bSIgor Russkikh struct qed_devlink *qed_dl = devlink_priv(dl); 6952306deeSIgor Russkikh struct qed_dev *cdev; 7052306deeSIgor Russkikh 7152306deeSIgor Russkikh cdev = qed_dl->cdev; 7252306deeSIgor Russkikh ctx->val.vbool = cdev->iwarp_cmt; 7352306deeSIgor Russkikh 7452306deeSIgor Russkikh return 0; 7552306deeSIgor Russkikh } 7652306deeSIgor Russkikh 7752306deeSIgor Russkikh static int qed_dl_param_set(struct devlink *dl, u32 id, 7852306deeSIgor Russkikh struct devlink_param_gset_ctx *ctx) 7952306deeSIgor Russkikh { 80755f982bSIgor Russkikh struct qed_devlink *qed_dl = devlink_priv(dl); 8152306deeSIgor Russkikh struct qed_dev *cdev; 8252306deeSIgor Russkikh 8352306deeSIgor Russkikh cdev = qed_dl->cdev; 8452306deeSIgor Russkikh cdev->iwarp_cmt = ctx->val.vbool; 8552306deeSIgor Russkikh 8652306deeSIgor Russkikh return 0; 8752306deeSIgor Russkikh } 8852306deeSIgor Russkikh 8952306deeSIgor Russkikh static const struct devlink_param qed_devlink_params[] = { 9052306deeSIgor Russkikh DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT, 9152306deeSIgor Russkikh "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL, 9252306deeSIgor Russkikh BIT(DEVLINK_PARAM_CMODE_RUNTIME), 9352306deeSIgor Russkikh qed_dl_param_get, qed_dl_param_set, NULL), 9452306deeSIgor Russkikh }; 9552306deeSIgor Russkikh 9653916a67SIgor Russkikh static int qed_devlink_info_get(struct devlink *devlink, 9753916a67SIgor Russkikh struct devlink_info_req *req, 9853916a67SIgor Russkikh struct netlink_ext_ack *extack) 9953916a67SIgor Russkikh { 10053916a67SIgor Russkikh struct qed_devlink *qed_dl = devlink_priv(devlink); 10153916a67SIgor Russkikh struct qed_dev *cdev = qed_dl->cdev; 10253916a67SIgor Russkikh struct qed_dev_info *dev_info; 10353916a67SIgor Russkikh char buf[100]; 10453916a67SIgor Russkikh int err; 10553916a67SIgor Russkikh 10653916a67SIgor Russkikh dev_info = &cdev->common_dev_info; 10753916a67SIgor Russkikh 10853916a67SIgor Russkikh err = devlink_info_driver_name_put(req, KBUILD_MODNAME); 10953916a67SIgor Russkikh if (err) 11053916a67SIgor Russkikh return err; 11153916a67SIgor Russkikh 11253916a67SIgor Russkikh memcpy(buf, cdev->hwfns[0].hw_info.part_num, sizeof(cdev->hwfns[0].hw_info.part_num)); 11353916a67SIgor Russkikh buf[sizeof(cdev->hwfns[0].hw_info.part_num)] = 0; 11453916a67SIgor Russkikh 11553916a67SIgor Russkikh if (buf[0]) { 11653916a67SIgor Russkikh err = devlink_info_board_serial_number_put(req, buf); 11753916a67SIgor Russkikh if (err) 11853916a67SIgor Russkikh return err; 11953916a67SIgor Russkikh } 12053916a67SIgor Russkikh 12153916a67SIgor Russkikh snprintf(buf, sizeof(buf), "%d.%d.%d.%d", 12253916a67SIgor Russkikh GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_3), 12353916a67SIgor Russkikh GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_2), 12453916a67SIgor Russkikh GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_1), 12553916a67SIgor Russkikh GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_0)); 12653916a67SIgor Russkikh 12753916a67SIgor Russkikh err = devlink_info_version_stored_put(req, 12853916a67SIgor Russkikh DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, buf); 12953916a67SIgor Russkikh if (err) 13053916a67SIgor Russkikh return err; 13153916a67SIgor Russkikh 13253916a67SIgor Russkikh snprintf(buf, sizeof(buf), "%d.%d.%d.%d", 13353916a67SIgor Russkikh dev_info->fw_major, 13453916a67SIgor Russkikh dev_info->fw_minor, 13553916a67SIgor Russkikh dev_info->fw_rev, 13653916a67SIgor Russkikh dev_info->fw_eng); 13753916a67SIgor Russkikh 13853916a67SIgor Russkikh return devlink_info_version_running_put(req, 13953916a67SIgor Russkikh DEVLINK_INFO_VERSION_GENERIC_FW_APP, buf); 14053916a67SIgor Russkikh } 14153916a67SIgor Russkikh 14253916a67SIgor Russkikh static const struct devlink_ops qed_dl_ops = { 14353916a67SIgor Russkikh .info_get = qed_devlink_info_get, 14453916a67SIgor Russkikh }; 14552306deeSIgor Russkikh 146755f982bSIgor Russkikh struct devlink *qed_devlink_register(struct qed_dev *cdev) 14752306deeSIgor Russkikh { 14852306deeSIgor Russkikh union devlink_param_value value; 149755f982bSIgor Russkikh struct qed_devlink *qdevlink; 15052306deeSIgor Russkikh struct devlink *dl; 15152306deeSIgor Russkikh int rc; 15252306deeSIgor Russkikh 153755f982bSIgor Russkikh dl = devlink_alloc(&qed_dl_ops, sizeof(struct qed_devlink)); 15452306deeSIgor Russkikh if (!dl) 155755f982bSIgor Russkikh return ERR_PTR(-ENOMEM); 15652306deeSIgor Russkikh 157755f982bSIgor Russkikh qdevlink = devlink_priv(dl); 158755f982bSIgor Russkikh qdevlink->cdev = cdev; 15952306deeSIgor Russkikh 16052306deeSIgor Russkikh rc = devlink_register(dl, &cdev->pdev->dev); 16152306deeSIgor Russkikh if (rc) 16252306deeSIgor Russkikh goto err_free; 16352306deeSIgor Russkikh 16452306deeSIgor Russkikh rc = devlink_params_register(dl, qed_devlink_params, 16552306deeSIgor Russkikh ARRAY_SIZE(qed_devlink_params)); 16652306deeSIgor Russkikh if (rc) 16752306deeSIgor Russkikh goto err_unregister; 16852306deeSIgor Russkikh 16952306deeSIgor Russkikh value.vbool = false; 17052306deeSIgor Russkikh devlink_param_driverinit_value_set(dl, 17152306deeSIgor Russkikh QED_DEVLINK_PARAM_ID_IWARP_CMT, 17252306deeSIgor Russkikh value); 17352306deeSIgor Russkikh 17452306deeSIgor Russkikh devlink_params_publish(dl); 17552306deeSIgor Russkikh cdev->iwarp_cmt = false; 17652306deeSIgor Russkikh 1779524067bSIgor Russkikh qed_fw_reporters_create(dl); 1789524067bSIgor Russkikh 179755f982bSIgor Russkikh return dl; 18052306deeSIgor Russkikh 18152306deeSIgor Russkikh err_unregister: 18252306deeSIgor Russkikh devlink_unregister(dl); 18352306deeSIgor Russkikh 18452306deeSIgor Russkikh err_free: 18552306deeSIgor Russkikh devlink_free(dl); 18652306deeSIgor Russkikh 187755f982bSIgor Russkikh return ERR_PTR(rc); 18852306deeSIgor Russkikh } 18952306deeSIgor Russkikh 190755f982bSIgor Russkikh void qed_devlink_unregister(struct devlink *devlink) 19152306deeSIgor Russkikh { 192755f982bSIgor Russkikh if (!devlink) 19352306deeSIgor Russkikh return; 19452306deeSIgor Russkikh 1959524067bSIgor Russkikh qed_fw_reporters_destroy(devlink); 1969524067bSIgor Russkikh 197755f982bSIgor Russkikh devlink_params_unregister(devlink, qed_devlink_params, 19852306deeSIgor Russkikh ARRAY_SIZE(qed_devlink_params)); 19952306deeSIgor Russkikh 200755f982bSIgor Russkikh devlink_unregister(devlink); 201755f982bSIgor Russkikh devlink_free(devlink); 20252306deeSIgor Russkikh } 203