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"
18 static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
19 struct devlink_fmsg *fmsg)
21 struct bnxt *bp = devlink_health_reporter_priv(reporter);
22 struct bnxt_fw_health *health = bp->fw_health;
23 u32 val, health_status;
26 if (!health || test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
29 val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
30 health_status = val & 0xffff;
32 if (health_status == BNXT_FW_STATUS_HEALTHY) {
33 rc = devlink_fmsg_string_pair_put(fmsg, "FW status",
37 } else if (health_status < BNXT_FW_STATUS_HEALTHY) {
38 rc = devlink_fmsg_string_pair_put(fmsg, "FW status",
39 "Not yet completed initialization;");
42 } else if (health_status > BNXT_FW_STATUS_HEALTHY) {
43 rc = devlink_fmsg_string_pair_put(fmsg, "FW status",
44 "Encountered fatal error and cannot recover;");
50 rc = devlink_fmsg_u32_pair_put(fmsg, "Error", val >> 16);
55 val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
56 rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val);
63 static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
65 .diagnose = bnxt_fw_reporter_diagnose,
68 static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
71 struct bnxt *bp = devlink_health_reporter_priv(reporter);
81 struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
83 .recover = bnxt_fw_reset_recover,
86 static void bnxt_dl_fw_reporters_create(struct bnxt *bp)
88 struct bnxt_fw_health *health = bp->fw_health;
94 devlink_health_reporter_create(bp->dl, &bnxt_dl_fw_reporter_ops,
96 if (IS_ERR(health->fw_reporter)) {
97 netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
98 PTR_ERR(health->fw_reporter));
99 health->fw_reporter = NULL;
102 health->fw_reset_reporter =
103 devlink_health_reporter_create(bp->dl,
104 &bnxt_dl_fw_reset_reporter_ops,
106 if (IS_ERR(health->fw_reset_reporter)) {
107 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
108 PTR_ERR(health->fw_reset_reporter));
109 health->fw_reset_reporter = NULL;
113 static void bnxt_dl_fw_reporters_destroy(struct bnxt *bp)
115 struct bnxt_fw_health *health = bp->fw_health;
120 if (health->fw_reporter)
121 devlink_health_reporter_destroy(health->fw_reporter);
123 if (health->fw_reset_reporter)
124 devlink_health_reporter_destroy(health->fw_reset_reporter);
127 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
129 struct bnxt_fw_health *fw_health = bp->fw_health;
130 struct bnxt_fw_reporter_ctx fw_reporter_ctx;
135 fw_reporter_ctx.sp_event = event;
137 case BNXT_FW_RESET_NOTIFY_SP_EVENT:
138 if (!fw_health->fw_reset_reporter)
141 devlink_health_report(fw_health->fw_reset_reporter,
142 "FW non-fatal reset event received",
148 static const struct devlink_ops bnxt_dl_ops = {
149 #ifdef CONFIG_BNXT_SRIOV
150 .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
151 .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
152 #endif /* CONFIG_BNXT_SRIOV */
155 enum bnxt_dl_param_id {
156 BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
157 BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
160 static const struct bnxt_dl_nvm_param nvm_params[] = {
161 {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
162 BNXT_NVM_SHARED_CFG, 1},
163 {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
164 BNXT_NVM_SHARED_CFG, 1},
165 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
166 NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10},
167 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
168 NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7},
169 {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
170 BNXT_NVM_SHARED_CFG, 1},
173 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
174 int msg_len, union devlink_param_value *val)
176 struct hwrm_nvm_get_variable_input *req = msg;
177 void *data_addr = NULL, *buf = NULL;
178 struct bnxt_dl_nvm_param nvm_param;
179 int bytesize, idx = 0, rc, i;
180 dma_addr_t data_dma_addr;
182 /* Get/Set NVM CFG parameter is supported only on PFs */
186 for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
187 if (nvm_params[i].id == param_id) {
188 nvm_param = nvm_params[i];
193 if (i == ARRAY_SIZE(nvm_params))
196 if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
197 idx = bp->pf.port_id;
198 else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
199 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
201 bytesize = roundup(nvm_param.num_bits, BITS_PER_BYTE) / BITS_PER_BYTE;
204 if (nvm_param.num_bits == 1)
219 data_addr = dma_alloc_coherent(&bp->pdev->dev, bytesize,
220 &data_dma_addr, GFP_KERNEL);
224 req->dest_data_addr = cpu_to_le64(data_dma_addr);
225 req->data_len = cpu_to_le16(nvm_param.num_bits);
226 req->option_num = cpu_to_le16(nvm_param.offset);
227 req->index_0 = cpu_to_le16(idx);
229 req->dimensions = cpu_to_le16(1);
231 if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
232 memcpy(data_addr, buf, bytesize);
233 rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
235 rc = hwrm_send_message_silent(bp, msg, msg_len,
238 if (!rc && req->req_type == cpu_to_le16(HWRM_NVM_GET_VARIABLE))
239 memcpy(buf, data_addr, bytesize);
241 dma_free_coherent(&bp->pdev->dev, bytesize, data_addr, data_dma_addr);
243 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
247 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
248 struct devlink_param_gset_ctx *ctx)
250 struct hwrm_nvm_get_variable_input req = {0};
251 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
254 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
255 rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
257 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
258 ctx->val.vbool = !ctx->val.vbool;
263 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
264 struct devlink_param_gset_ctx *ctx)
266 struct hwrm_nvm_set_variable_input req = {0};
267 struct bnxt *bp = bnxt_get_bp_from_dl(dl);
269 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
271 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
272 ctx->val.vbool = !ctx->val.vbool;
274 return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
277 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
278 union devlink_param_value val,
279 struct netlink_ext_ack *extack)
283 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
284 max_val = BNXT_MSIX_VEC_MAX;
286 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
287 max_val = BNXT_MSIX_VEC_MIN_MAX;
289 if (val.vu32 > max_val) {
290 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
297 static const struct devlink_param bnxt_dl_params[] = {
298 DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
299 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
300 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
302 DEVLINK_PARAM_GENERIC(IGNORE_ARI,
303 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
304 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
306 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
307 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
308 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
309 bnxt_dl_msix_validate),
310 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
311 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
312 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
313 bnxt_dl_msix_validate),
314 DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
315 "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
316 BIT(DEVLINK_PARAM_CMODE_PERMANENT),
317 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
321 static const struct devlink_param bnxt_dl_port_params[] = {
324 int bnxt_dl_register(struct bnxt *bp)
329 if (bp->hwrm_spec_code < 0x10600) {
330 netdev_warn(bp->dev, "Firmware does not support NVM params");
334 dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
336 netdev_warn(bp->dev, "devlink_alloc failed");
340 bnxt_link_bp_to_dl(bp, dl);
342 /* Add switchdev eswitch mode setting, if SRIOV supported */
343 if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
344 bp->hwrm_spec_code > 0x10803)
345 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
347 rc = devlink_register(dl, &bp->pdev->dev);
349 netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
353 rc = devlink_params_register(dl, bnxt_dl_params,
354 ARRAY_SIZE(bnxt_dl_params));
356 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
361 devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
362 bp->pf.port_id, false, 0,
363 bp->switch_id, sizeof(bp->switch_id));
364 rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
366 netdev_err(bp->dev, "devlink_port_register failed");
367 goto err_dl_param_unreg;
369 devlink_port_type_eth_set(&bp->dl_port, bp->dev);
371 rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
372 ARRAY_SIZE(bnxt_dl_port_params));
374 netdev_err(bp->dev, "devlink_port_params_register failed");
375 goto err_dl_port_unreg;
378 devlink_params_publish(dl);
380 bnxt_dl_fw_reporters_create(bp);
385 devlink_port_unregister(&bp->dl_port);
387 devlink_params_unregister(dl, bnxt_dl_params,
388 ARRAY_SIZE(bnxt_dl_params));
390 devlink_unregister(dl);
392 bnxt_link_bp_to_dl(bp, NULL);
397 void bnxt_dl_unregister(struct bnxt *bp)
399 struct devlink *dl = bp->dl;
404 bnxt_dl_fw_reporters_destroy(bp);
405 devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
406 ARRAY_SIZE(bnxt_dl_port_params));
407 devlink_port_unregister(&bp->dl_port);
408 devlink_params_unregister(dl, bnxt_dl_params,
409 ARRAY_SIZE(bnxt_dl_params));
410 devlink_unregister(dl);