Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Marvell/Qlogic FastLinQ NIC driver
0003  *
0004  * Copyright (C) 2020 Marvell International Ltd.
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/qed/qed_if.h>
0009 #include <linux/vmalloc.h>
0010 #include "qed.h"
0011 #include "qed_devlink.h"
0012 
0013 enum qed_devlink_param_id {
0014     QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
0015     QED_DEVLINK_PARAM_ID_IWARP_CMT,
0016 };
0017 
0018 struct qed_fw_fatal_ctx {
0019     enum qed_hw_err_type err_type;
0020 };
0021 
0022 int qed_report_fatal_error(struct devlink *devlink, enum qed_hw_err_type err_type)
0023 {
0024     struct qed_devlink *qdl = devlink_priv(devlink);
0025     struct qed_fw_fatal_ctx fw_fatal_ctx = {
0026         .err_type = err_type,
0027     };
0028 
0029     if (qdl->fw_reporter)
0030         devlink_health_report(qdl->fw_reporter,
0031                       "Fatal error occurred", &fw_fatal_ctx);
0032 
0033     return 0;
0034 }
0035 
0036 static int
0037 qed_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter,
0038                struct devlink_fmsg *fmsg, void *priv_ctx,
0039                struct netlink_ext_ack *extack)
0040 {
0041     struct qed_devlink *qdl = devlink_health_reporter_priv(reporter);
0042     struct qed_fw_fatal_ctx *fw_fatal_ctx = priv_ctx;
0043     struct qed_dev *cdev = qdl->cdev;
0044     u32 dbg_data_buf_size;
0045     u8 *p_dbg_data_buf;
0046     int err;
0047 
0048     /* Having context means that was a dump request after fatal,
0049      * so we enable extra debugging while gathering the dump,
0050      * just in case
0051      */
0052     cdev->print_dbg_data = fw_fatal_ctx ? true : false;
0053 
0054     dbg_data_buf_size = qed_dbg_all_data_size(cdev);
0055     p_dbg_data_buf = vzalloc(dbg_data_buf_size);
0056     if (!p_dbg_data_buf) {
0057         DP_NOTICE(cdev,
0058               "Failed to allocate memory for a debug data buffer\n");
0059         return -ENOMEM;
0060     }
0061 
0062     err = qed_dbg_all_data(cdev, p_dbg_data_buf);
0063     if (err) {
0064         DP_NOTICE(cdev, "Failed to obtain debug data\n");
0065         vfree(p_dbg_data_buf);
0066         return err;
0067     }
0068 
0069     err = devlink_fmsg_binary_pair_put(fmsg, "dump_data",
0070                        p_dbg_data_buf, dbg_data_buf_size);
0071 
0072     vfree(p_dbg_data_buf);
0073 
0074     return err;
0075 }
0076 
0077 static int
0078 qed_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter,
0079                   void *priv_ctx,
0080                   struct netlink_ext_ack *extack)
0081 {
0082     struct qed_devlink *qdl = devlink_health_reporter_priv(reporter);
0083     struct qed_dev *cdev = qdl->cdev;
0084 
0085     qed_recovery_process(cdev);
0086 
0087     return 0;
0088 }
0089 
0090 static const struct devlink_health_reporter_ops qed_fw_fatal_reporter_ops = {
0091         .name = "fw_fatal",
0092         .recover = qed_fw_fatal_reporter_recover,
0093         .dump = qed_fw_fatal_reporter_dump,
0094 };
0095 
0096 #define QED_REPORTER_FW_GRACEFUL_PERIOD 0
0097 
0098 void qed_fw_reporters_create(struct devlink *devlink)
0099 {
0100     struct qed_devlink *dl = devlink_priv(devlink);
0101 
0102     dl->fw_reporter = devlink_health_reporter_create(devlink, &qed_fw_fatal_reporter_ops,
0103                              QED_REPORTER_FW_GRACEFUL_PERIOD, dl);
0104     if (IS_ERR(dl->fw_reporter)) {
0105         DP_NOTICE(dl->cdev, "Failed to create fw reporter, err = %ld\n",
0106               PTR_ERR(dl->fw_reporter));
0107         dl->fw_reporter = NULL;
0108     }
0109 }
0110 
0111 void qed_fw_reporters_destroy(struct devlink *devlink)
0112 {
0113     struct qed_devlink *dl = devlink_priv(devlink);
0114     struct devlink_health_reporter *rep;
0115 
0116     rep = dl->fw_reporter;
0117 
0118     if (!IS_ERR_OR_NULL(rep))
0119         devlink_health_reporter_destroy(rep);
0120 }
0121 
0122 static int qed_dl_param_get(struct devlink *dl, u32 id,
0123                 struct devlink_param_gset_ctx *ctx)
0124 {
0125     struct qed_devlink *qed_dl = devlink_priv(dl);
0126     struct qed_dev *cdev;
0127 
0128     cdev = qed_dl->cdev;
0129     ctx->val.vbool = cdev->iwarp_cmt;
0130 
0131     return 0;
0132 }
0133 
0134 static int qed_dl_param_set(struct devlink *dl, u32 id,
0135                 struct devlink_param_gset_ctx *ctx)
0136 {
0137     struct qed_devlink *qed_dl = devlink_priv(dl);
0138     struct qed_dev *cdev;
0139 
0140     cdev = qed_dl->cdev;
0141     cdev->iwarp_cmt = ctx->val.vbool;
0142 
0143     return 0;
0144 }
0145 
0146 static const struct devlink_param qed_devlink_params[] = {
0147     DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT,
0148                  "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL,
0149                  BIT(DEVLINK_PARAM_CMODE_RUNTIME),
0150                  qed_dl_param_get, qed_dl_param_set, NULL),
0151 };
0152 
0153 static int qed_devlink_info_get(struct devlink *devlink,
0154                 struct devlink_info_req *req,
0155                 struct netlink_ext_ack *extack)
0156 {
0157     struct qed_devlink *qed_dl = devlink_priv(devlink);
0158     struct qed_dev *cdev = qed_dl->cdev;
0159     struct qed_dev_info *dev_info;
0160     char buf[100];
0161     int err;
0162 
0163     dev_info = &cdev->common_dev_info;
0164 
0165     err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
0166     if (err)
0167         return err;
0168 
0169     memcpy(buf, cdev->hwfns[0].hw_info.part_num, sizeof(cdev->hwfns[0].hw_info.part_num));
0170     buf[sizeof(cdev->hwfns[0].hw_info.part_num)] = 0;
0171 
0172     if (buf[0]) {
0173         err = devlink_info_board_serial_number_put(req, buf);
0174         if (err)
0175             return err;
0176     }
0177 
0178     snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
0179          GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_3),
0180          GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_2),
0181          GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_1),
0182          GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_0));
0183 
0184     err = devlink_info_version_stored_put(req,
0185                           DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, buf);
0186     if (err)
0187         return err;
0188 
0189     snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
0190          dev_info->fw_major,
0191          dev_info->fw_minor,
0192          dev_info->fw_rev,
0193          dev_info->fw_eng);
0194 
0195     return devlink_info_version_running_put(req,
0196                         DEVLINK_INFO_VERSION_GENERIC_FW_APP, buf);
0197 }
0198 
0199 static const struct devlink_ops qed_dl_ops = {
0200     .info_get = qed_devlink_info_get,
0201 };
0202 
0203 struct devlink *qed_devlink_register(struct qed_dev *cdev)
0204 {
0205     union devlink_param_value value;
0206     struct qed_devlink *qdevlink;
0207     struct devlink *dl;
0208     int rc;
0209 
0210     dl = devlink_alloc(&qed_dl_ops, sizeof(struct qed_devlink),
0211                &cdev->pdev->dev);
0212     if (!dl)
0213         return ERR_PTR(-ENOMEM);
0214 
0215     qdevlink = devlink_priv(dl);
0216     qdevlink->cdev = cdev;
0217 
0218     rc = devlink_params_register(dl, qed_devlink_params,
0219                      ARRAY_SIZE(qed_devlink_params));
0220     if (rc)
0221         goto err_unregister;
0222 
0223     value.vbool = false;
0224     devlink_param_driverinit_value_set(dl,
0225                        QED_DEVLINK_PARAM_ID_IWARP_CMT,
0226                        value);
0227 
0228     cdev->iwarp_cmt = false;
0229 
0230     qed_fw_reporters_create(dl);
0231     devlink_register(dl);
0232     return dl;
0233 
0234 err_unregister:
0235     devlink_free(dl);
0236 
0237     return ERR_PTR(rc);
0238 }
0239 
0240 void qed_devlink_unregister(struct devlink *devlink)
0241 {
0242     if (!devlink)
0243         return;
0244 
0245     devlink_unregister(devlink);
0246     qed_fw_reporters_destroy(devlink);
0247 
0248     devlink_params_unregister(devlink, qed_devlink_params,
0249                   ARRAY_SIZE(qed_devlink_params));
0250 
0251     devlink_free(devlink);
0252 }