1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Marvell/Qlogic FastLinQ NIC driver 3 * 4 * Copyright (C) 2020 Marvell International Ltd. 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/qed/qed_if.h> 9 #include "qed.h" 10 #include "qed_devlink.h" 11 12 enum qed_devlink_param_id { 13 QED_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 14 QED_DEVLINK_PARAM_ID_IWARP_CMT, 15 }; 16 17 struct qed_fw_fatal_ctx { 18 enum qed_hw_err_type err_type; 19 }; 20 21 int qed_report_fatal_error(struct devlink *devlink, enum qed_hw_err_type err_type) 22 { 23 struct qed_devlink *qdl = devlink_priv(devlink); 24 struct qed_fw_fatal_ctx fw_fatal_ctx = { 25 .err_type = err_type, 26 }; 27 28 if (qdl->fw_reporter) 29 devlink_health_report(qdl->fw_reporter, 30 "Fatal error occurred", &fw_fatal_ctx); 31 32 return 0; 33 } 34 35 static const struct devlink_health_reporter_ops qed_fw_fatal_reporter_ops = { 36 .name = "fw_fatal", 37 }; 38 39 #define QED_REPORTER_FW_GRACEFUL_PERIOD 1200000 40 41 void qed_fw_reporters_create(struct devlink *devlink) 42 { 43 struct qed_devlink *dl = devlink_priv(devlink); 44 45 dl->fw_reporter = devlink_health_reporter_create(devlink, &qed_fw_fatal_reporter_ops, 46 QED_REPORTER_FW_GRACEFUL_PERIOD, dl); 47 if (IS_ERR(dl->fw_reporter)) { 48 DP_NOTICE(dl->cdev, "Failed to create fw reporter, err = %ld\n", 49 PTR_ERR(dl->fw_reporter)); 50 dl->fw_reporter = NULL; 51 } 52 } 53 54 void qed_fw_reporters_destroy(struct devlink *devlink) 55 { 56 struct qed_devlink *dl = devlink_priv(devlink); 57 struct devlink_health_reporter *rep; 58 59 rep = dl->fw_reporter; 60 61 if (!IS_ERR_OR_NULL(rep)) 62 devlink_health_reporter_destroy(rep); 63 } 64 65 static int qed_dl_param_get(struct devlink *dl, u32 id, 66 struct devlink_param_gset_ctx *ctx) 67 { 68 struct qed_devlink *qed_dl = devlink_priv(dl); 69 struct qed_dev *cdev; 70 71 cdev = qed_dl->cdev; 72 ctx->val.vbool = cdev->iwarp_cmt; 73 74 return 0; 75 } 76 77 static int qed_dl_param_set(struct devlink *dl, u32 id, 78 struct devlink_param_gset_ctx *ctx) 79 { 80 struct qed_devlink *qed_dl = devlink_priv(dl); 81 struct qed_dev *cdev; 82 83 cdev = qed_dl->cdev; 84 cdev->iwarp_cmt = ctx->val.vbool; 85 86 return 0; 87 } 88 89 static const struct devlink_param qed_devlink_params[] = { 90 DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT, 91 "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL, 92 BIT(DEVLINK_PARAM_CMODE_RUNTIME), 93 qed_dl_param_get, qed_dl_param_set, NULL), 94 }; 95 96 static int qed_devlink_info_get(struct devlink *devlink, 97 struct devlink_info_req *req, 98 struct netlink_ext_ack *extack) 99 { 100 struct qed_devlink *qed_dl = devlink_priv(devlink); 101 struct qed_dev *cdev = qed_dl->cdev; 102 struct qed_dev_info *dev_info; 103 char buf[100]; 104 int err; 105 106 dev_info = &cdev->common_dev_info; 107 108 err = devlink_info_driver_name_put(req, KBUILD_MODNAME); 109 if (err) 110 return err; 111 112 memcpy(buf, cdev->hwfns[0].hw_info.part_num, sizeof(cdev->hwfns[0].hw_info.part_num)); 113 buf[sizeof(cdev->hwfns[0].hw_info.part_num)] = 0; 114 115 if (buf[0]) { 116 err = devlink_info_board_serial_number_put(req, buf); 117 if (err) 118 return err; 119 } 120 121 snprintf(buf, sizeof(buf), "%d.%d.%d.%d", 122 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_3), 123 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_2), 124 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_1), 125 GET_MFW_FIELD(dev_info->mfw_rev, QED_MFW_VERSION_0)); 126 127 err = devlink_info_version_stored_put(req, 128 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, buf); 129 if (err) 130 return err; 131 132 snprintf(buf, sizeof(buf), "%d.%d.%d.%d", 133 dev_info->fw_major, 134 dev_info->fw_minor, 135 dev_info->fw_rev, 136 dev_info->fw_eng); 137 138 return devlink_info_version_running_put(req, 139 DEVLINK_INFO_VERSION_GENERIC_FW_APP, buf); 140 } 141 142 static const struct devlink_ops qed_dl_ops = { 143 .info_get = qed_devlink_info_get, 144 }; 145 146 struct devlink *qed_devlink_register(struct qed_dev *cdev) 147 { 148 union devlink_param_value value; 149 struct qed_devlink *qdevlink; 150 struct devlink *dl; 151 int rc; 152 153 dl = devlink_alloc(&qed_dl_ops, sizeof(struct qed_devlink)); 154 if (!dl) 155 return ERR_PTR(-ENOMEM); 156 157 qdevlink = devlink_priv(dl); 158 qdevlink->cdev = cdev; 159 160 rc = devlink_register(dl, &cdev->pdev->dev); 161 if (rc) 162 goto err_free; 163 164 rc = devlink_params_register(dl, qed_devlink_params, 165 ARRAY_SIZE(qed_devlink_params)); 166 if (rc) 167 goto err_unregister; 168 169 value.vbool = false; 170 devlink_param_driverinit_value_set(dl, 171 QED_DEVLINK_PARAM_ID_IWARP_CMT, 172 value); 173 174 devlink_params_publish(dl); 175 cdev->iwarp_cmt = false; 176 177 qed_fw_reporters_create(dl); 178 179 return dl; 180 181 err_unregister: 182 devlink_unregister(dl); 183 184 err_free: 185 devlink_free(dl); 186 187 return ERR_PTR(rc); 188 } 189 190 void qed_devlink_unregister(struct devlink *devlink) 191 { 192 if (!devlink) 193 return; 194 195 qed_fw_reporters_destroy(devlink); 196 197 devlink_params_unregister(devlink, qed_devlink_params, 198 ARRAY_SIZE(qed_devlink_params)); 199 200 devlink_unregister(devlink); 201 devlink_free(devlink); 202 } 203