1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Marvell/Qlogic FastLinQ NIC driver
4 * Copyright (C) 2020 Marvell International Ltd.
7 #include <linux/kernel.h>
8 #include <linux/qed/qed_if.h>
9 #include <linux/vmalloc.h>
11 #include "qed_devlink.h"
13 enum qed_devlink_param_id
{
14 QED_DEVLINK_PARAM_ID_BASE
= DEVLINK_PARAM_GENERIC_ID_MAX
,
15 QED_DEVLINK_PARAM_ID_IWARP_CMT
,
18 struct qed_fw_fatal_ctx
{
19 enum qed_hw_err_type err_type
;
22 int qed_report_fatal_error(struct devlink
*devlink
, enum qed_hw_err_type err_type
)
24 struct qed_devlink
*qdl
= devlink_priv(devlink
);
25 struct qed_fw_fatal_ctx fw_fatal_ctx
= {
30 devlink_health_report(qdl
->fw_reporter
,
31 "Fatal error occurred", &fw_fatal_ctx
);
37 qed_fw_fatal_reporter_dump(struct devlink_health_reporter
*reporter
,
38 struct devlink_fmsg
*fmsg
, void *priv_ctx
,
39 struct netlink_ext_ack
*extack
)
41 struct qed_devlink
*qdl
= devlink_health_reporter_priv(reporter
);
42 struct qed_fw_fatal_ctx
*fw_fatal_ctx
= priv_ctx
;
43 struct qed_dev
*cdev
= qdl
->cdev
;
44 u32 dbg_data_buf_size
;
48 /* Having context means that was a dump request after fatal,
49 * so we enable extra debugging while gathering the dump,
52 cdev
->print_dbg_data
= fw_fatal_ctx
? true : false;
54 dbg_data_buf_size
= qed_dbg_all_data_size(cdev
);
55 p_dbg_data_buf
= vzalloc(dbg_data_buf_size
);
56 if (!p_dbg_data_buf
) {
58 "Failed to allocate memory for a debug data buffer\n");
62 err
= qed_dbg_all_data(cdev
, p_dbg_data_buf
);
64 DP_NOTICE(cdev
, "Failed to obtain debug data\n");
65 vfree(p_dbg_data_buf
);
69 devlink_fmsg_binary_pair_put(fmsg
, "dump_data", p_dbg_data_buf
,
72 vfree(p_dbg_data_buf
);
78 qed_fw_fatal_reporter_recover(struct devlink_health_reporter
*reporter
,
80 struct netlink_ext_ack
*extack
)
82 struct qed_devlink
*qdl
= devlink_health_reporter_priv(reporter
);
83 struct qed_dev
*cdev
= qdl
->cdev
;
85 qed_recovery_process(cdev
);
90 static const struct devlink_health_reporter_ops qed_fw_fatal_reporter_ops
= {
92 .recover
= qed_fw_fatal_reporter_recover
,
93 .dump
= qed_fw_fatal_reporter_dump
,
96 #define QED_REPORTER_FW_GRACEFUL_PERIOD 0
98 void qed_fw_reporters_create(struct devlink
*devlink
)
100 struct qed_devlink
*dl
= devlink_priv(devlink
);
102 dl
->fw_reporter
= devlink_health_reporter_create(devlink
, &qed_fw_fatal_reporter_ops
,
103 QED_REPORTER_FW_GRACEFUL_PERIOD
, dl
);
104 if (IS_ERR(dl
->fw_reporter
)) {
105 DP_NOTICE(dl
->cdev
, "Failed to create fw reporter, err = %ld\n",
106 PTR_ERR(dl
->fw_reporter
));
107 dl
->fw_reporter
= NULL
;
111 void qed_fw_reporters_destroy(struct devlink
*devlink
)
113 struct qed_devlink
*dl
= devlink_priv(devlink
);
114 struct devlink_health_reporter
*rep
;
116 rep
= dl
->fw_reporter
;
118 if (!IS_ERR_OR_NULL(rep
))
119 devlink_health_reporter_destroy(rep
);
122 static int qed_dl_param_get(struct devlink
*dl
, u32 id
,
123 struct devlink_param_gset_ctx
*ctx
)
125 struct qed_devlink
*qed_dl
= devlink_priv(dl
);
126 struct qed_dev
*cdev
;
129 ctx
->val
.vbool
= cdev
->iwarp_cmt
;
134 static int qed_dl_param_set(struct devlink
*dl
, u32 id
,
135 struct devlink_param_gset_ctx
*ctx
,
136 struct netlink_ext_ack
*extack
)
138 struct qed_devlink
*qed_dl
= devlink_priv(dl
);
139 struct qed_dev
*cdev
;
142 cdev
->iwarp_cmt
= ctx
->val
.vbool
;
147 static const struct devlink_param qed_devlink_params
[] = {
148 DEVLINK_PARAM_DRIVER(QED_DEVLINK_PARAM_ID_IWARP_CMT
,
149 "iwarp_cmt", DEVLINK_PARAM_TYPE_BOOL
,
150 BIT(DEVLINK_PARAM_CMODE_RUNTIME
),
151 qed_dl_param_get
, qed_dl_param_set
, NULL
),
154 static int qed_devlink_info_get(struct devlink
*devlink
,
155 struct devlink_info_req
*req
,
156 struct netlink_ext_ack
*extack
)
158 struct qed_devlink
*qed_dl
= devlink_priv(devlink
);
159 struct qed_dev
*cdev
= qed_dl
->cdev
;
160 struct qed_dev_info
*dev_info
;
164 dev_info
= &cdev
->common_dev_info
;
166 memcpy(buf
, cdev
->hwfns
[0].hw_info
.part_num
, sizeof(cdev
->hwfns
[0].hw_info
.part_num
));
167 buf
[sizeof(cdev
->hwfns
[0].hw_info
.part_num
)] = 0;
170 err
= devlink_info_board_serial_number_put(req
, buf
);
175 snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d",
176 GET_MFW_FIELD(dev_info
->mfw_rev
, QED_MFW_VERSION_3
),
177 GET_MFW_FIELD(dev_info
->mfw_rev
, QED_MFW_VERSION_2
),
178 GET_MFW_FIELD(dev_info
->mfw_rev
, QED_MFW_VERSION_1
),
179 GET_MFW_FIELD(dev_info
->mfw_rev
, QED_MFW_VERSION_0
));
181 err
= devlink_info_version_stored_put(req
,
182 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT
, buf
);
186 snprintf(buf
, sizeof(buf
), "%d.%d.%d.%d",
192 return devlink_info_version_running_put(req
,
193 DEVLINK_INFO_VERSION_GENERIC_FW_APP
, buf
);
196 static const struct devlink_ops qed_dl_ops
= {
197 .info_get
= qed_devlink_info_get
,
200 struct devlink
*qed_devlink_register(struct qed_dev
*cdev
)
202 struct qed_devlink
*qdevlink
;
206 dl
= devlink_alloc(&qed_dl_ops
, sizeof(struct qed_devlink
),
209 return ERR_PTR(-ENOMEM
);
211 qdevlink
= devlink_priv(dl
);
212 qdevlink
->cdev
= cdev
;
214 rc
= devlink_params_register(dl
, qed_devlink_params
,
215 ARRAY_SIZE(qed_devlink_params
));
219 cdev
->iwarp_cmt
= false;
221 qed_fw_reporters_create(dl
);
222 devlink_register(dl
);
231 void qed_devlink_unregister(struct devlink
*devlink
)
236 devlink_unregister(devlink
);
237 qed_fw_reporters_destroy(devlink
);
239 devlink_params_unregister(devlink
, qed_devlink_params
,
240 ARRAY_SIZE(qed_devlink_params
));
242 devlink_free(devlink
);