Commit | Line | Data |
---|---|---|
3c467bf3 SL |
1 | /* Broadcom NetXtreme-C/E network driver. |
2 | * | |
3 | * Copyright (c) 2017 Broadcom Limited | |
4 | * | |
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. | |
8 | */ | |
9 | ||
10 | #include <linux/pci.h> | |
11 | #include <linux/netdevice.h> | |
477edb78 | 12 | #include <net/devlink.h> |
3c467bf3 SL |
13 | #include "bnxt_hsi.h" |
14 | #include "bnxt.h" | |
3c8c20db | 15 | #include "bnxt_hwrm.h" |
3c467bf3 SL |
16 | #include "bnxt_vfr.h" |
17 | #include "bnxt_devlink.h" | |
d168f328 | 18 | #include "bnxt_ethtool.h" |
228ea8c1 EP |
19 | #include "bnxt_ulp.h" |
20 | #include "bnxt_ptp.h" | |
188876db | 21 | #include "bnxt_coredump.h" |
d168f328 | 22 | |
aadb0b1a EP |
23 | static void __bnxt_fw_recover(struct bnxt *bp) |
24 | { | |
25 | if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state) || | |
26 | test_bit(BNXT_STATE_FW_NON_FATAL_COND, &bp->state)) | |
27 | bnxt_fw_reset(bp); | |
28 | else | |
29 | bnxt_fw_exception(bp); | |
30 | } | |
31 | ||
d168f328 | 32 | static int |
bc75c054 JK |
33 | bnxt_dl_flash_update(struct devlink *dl, |
34 | struct devlink_flash_update_params *params, | |
35 | struct netlink_ext_ack *extack) | |
d168f328 VV |
36 | { |
37 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); | |
8159cbe3 | 38 | int rc; |
d168f328 | 39 | |
d168f328 VV |
40 | if (!BNXT_PF(bp)) { |
41 | NL_SET_ERR_MSG_MOD(extack, | |
42 | "flash update not supported from a VF"); | |
43 | return -EPERM; | |
44 | } | |
45 | ||
22ec3d23 | 46 | devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0); |
b44cfd4f | 47 | rc = bnxt_flash_package_from_fw_obj(bp->dev, params->fw, 0); |
8159cbe3 | 48 | if (!rc) |
22ec3d23 | 49 | devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0); |
8159cbe3 | 50 | else |
22ec3d23 | 51 | devlink_flash_update_status_notify(dl, "Flashing failed", NULL, 0, 0); |
8159cbe3 | 52 | return rc; |
d168f328 | 53 | } |
3c467bf3 | 54 | |
892a662f EP |
55 | static int bnxt_hwrm_remote_dev_reset_set(struct bnxt *bp, bool remote_reset) |
56 | { | |
57 | struct hwrm_func_cfg_input *req; | |
58 | int rc; | |
59 | ||
60 | if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF) | |
61 | return -EOPNOTSUPP; | |
62 | ||
63 | rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG); | |
64 | if (rc) | |
65 | return rc; | |
66 | ||
67 | req->fid = cpu_to_le16(0xffff); | |
68 | req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_HOT_RESET_IF_SUPPORT); | |
69 | if (remote_reset) | |
70 | req->flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_HOT_RESET_IF_EN_DIS); | |
71 | ||
72 | return hwrm_req_send(bp, req); | |
73 | } | |
74 | ||
8cc95ceb EP |
75 | static char *bnxt_health_severity_str(enum bnxt_health_severity severity) |
76 | { | |
77 | switch (severity) { | |
78 | case SEVERITY_NORMAL: return "normal"; | |
79 | case SEVERITY_WARNING: return "warning"; | |
80 | case SEVERITY_RECOVERABLE: return "recoverable"; | |
81 | case SEVERITY_FATAL: return "fatal"; | |
82 | default: return "unknown"; | |
83 | } | |
84 | } | |
85 | ||
86 | static char *bnxt_health_remedy_str(enum bnxt_health_remedy remedy) | |
87 | { | |
88 | switch (remedy) { | |
89 | case REMEDY_DEVLINK_RECOVER: return "devlink recover"; | |
90 | case REMEDY_POWER_CYCLE_DEVICE: return "device power cycle"; | |
91 | case REMEDY_POWER_CYCLE_HOST: return "host power cycle"; | |
92 | case REMEDY_FW_UPDATE: return "update firmware"; | |
93 | case REMEDY_HW_REPLACE: return "replace hardware"; | |
94 | default: return "unknown"; | |
95 | } | |
96 | } | |
97 | ||
2bb21b8d EP |
98 | static int bnxt_fw_diagnose(struct devlink_health_reporter *reporter, |
99 | struct devlink_fmsg *fmsg, | |
100 | struct netlink_ext_ack *extack) | |
6763c779 VV |
101 | { |
102 | struct bnxt *bp = devlink_health_reporter_priv(reporter); | |
8cc95ceb EP |
103 | struct bnxt_fw_health *h = bp->fw_health; |
104 | u32 fw_status, fw_resets; | |
6763c779 VV |
105 | int rc; |
106 | ||
0797c10d | 107 | if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) |
8cc95ceb | 108 | return devlink_fmsg_string_pair_put(fmsg, "Status", "recovering"); |
6763c779 | 109 | |
8cc95ceb EP |
110 | if (!h->status_reliable) |
111 | return devlink_fmsg_string_pair_put(fmsg, "Status", "unknown"); | |
6763c779 | 112 | |
8cc95ceb EP |
113 | mutex_lock(&h->lock); |
114 | fw_status = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG); | |
115 | if (BNXT_FW_IS_BOOTING(fw_status)) { | |
116 | rc = devlink_fmsg_string_pair_put(fmsg, "Status", "initializing"); | |
6763c779 | 117 | if (rc) |
8cc95ceb EP |
118 | goto unlock; |
119 | } else if (h->severity || fw_status != BNXT_FW_STATUS_HEALTHY) { | |
120 | if (!h->severity) { | |
121 | h->severity = SEVERITY_FATAL; | |
122 | h->remedy = REMEDY_POWER_CYCLE_DEVICE; | |
123 | h->diagnoses++; | |
124 | devlink_health_report(h->fw_reporter, | |
125 | "FW error diagnosed", h); | |
126 | } | |
127 | rc = devlink_fmsg_string_pair_put(fmsg, "Status", "error"); | |
6763c779 | 128 | if (rc) |
8cc95ceb EP |
129 | goto unlock; |
130 | rc = devlink_fmsg_u32_pair_put(fmsg, "Syndrome", fw_status); | |
131 | if (rc) | |
132 | goto unlock; | |
133 | } else { | |
134 | rc = devlink_fmsg_string_pair_put(fmsg, "Status", "healthy"); | |
135 | if (rc) | |
136 | goto unlock; | |
6763c779 VV |
137 | } |
138 | ||
8cc95ceb EP |
139 | rc = devlink_fmsg_string_pair_put(fmsg, "Severity", |
140 | bnxt_health_severity_str(h->severity)); | |
141 | if (rc) | |
142 | goto unlock; | |
143 | ||
144 | if (h->severity) { | |
145 | rc = devlink_fmsg_string_pair_put(fmsg, "Remedy", | |
146 | bnxt_health_remedy_str(h->remedy)); | |
6763c779 | 147 | if (rc) |
8cc95ceb EP |
148 | goto unlock; |
149 | if (h->remedy == REMEDY_DEVLINK_RECOVER) { | |
150 | rc = devlink_fmsg_string_pair_put(fmsg, "Impact", | |
151 | "traffic+ntuple_cfg"); | |
152 | if (rc) | |
153 | goto unlock; | |
154 | } | |
6763c779 VV |
155 | } |
156 | ||
8cc95ceb EP |
157 | unlock: |
158 | mutex_unlock(&h->lock); | |
159 | if (rc || !h->resets_reliable) | |
6763c779 VV |
160 | return rc; |
161 | ||
8cc95ceb EP |
162 | fw_resets = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG); |
163 | rc = devlink_fmsg_u32_pair_put(fmsg, "Resets", fw_resets); | |
164 | if (rc) | |
165 | return rc; | |
166 | rc = devlink_fmsg_u32_pair_put(fmsg, "Arrests", h->arrests); | |
167 | if (rc) | |
168 | return rc; | |
169 | rc = devlink_fmsg_u32_pair_put(fmsg, "Survivals", h->survivals); | |
170 | if (rc) | |
171 | return rc; | |
172 | rc = devlink_fmsg_u32_pair_put(fmsg, "Discoveries", h->discoveries); | |
173 | if (rc) | |
174 | return rc; | |
175 | rc = devlink_fmsg_u32_pair_put(fmsg, "Fatalities", h->fatalities); | |
176 | if (rc) | |
177 | return rc; | |
178 | return devlink_fmsg_u32_pair_put(fmsg, "Diagnoses", h->diagnoses); | |
6763c779 VV |
179 | } |
180 | ||
188876db EP |
181 | static int bnxt_fw_dump(struct devlink_health_reporter *reporter, |
182 | struct devlink_fmsg *fmsg, void *priv_ctx, | |
183 | struct netlink_ext_ack *extack) | |
184 | { | |
185 | struct bnxt *bp = devlink_health_reporter_priv(reporter); | |
186 | u32 dump_len; | |
187 | void *data; | |
188 | int rc; | |
189 | ||
190 | /* TODO: no firmware dump support in devlink_health_report() context */ | |
191 | if (priv_ctx) | |
192 | return -EOPNOTSUPP; | |
193 | ||
194 | dump_len = bnxt_get_coredump_length(bp, BNXT_DUMP_LIVE); | |
195 | if (!dump_len) | |
196 | return -EIO; | |
197 | ||
198 | data = vmalloc(dump_len); | |
199 | if (!data) | |
200 | return -ENOMEM; | |
201 | ||
202 | rc = bnxt_get_coredump(bp, BNXT_DUMP_LIVE, data, &dump_len); | |
203 | if (!rc) { | |
204 | rc = devlink_fmsg_pair_nest_start(fmsg, "core"); | |
205 | if (rc) | |
206 | goto exit; | |
207 | rc = devlink_fmsg_binary_pair_put(fmsg, "data", data, dump_len); | |
208 | if (rc) | |
209 | goto exit; | |
210 | rc = devlink_fmsg_u32_pair_put(fmsg, "size", dump_len); | |
211 | if (rc) | |
212 | goto exit; | |
213 | rc = devlink_fmsg_pair_nest_end(fmsg); | |
214 | } | |
215 | ||
216 | exit: | |
217 | vfree(data); | |
218 | return rc; | |
219 | } | |
220 | ||
2bb21b8d EP |
221 | static int bnxt_fw_recover(struct devlink_health_reporter *reporter, |
222 | void *priv_ctx, | |
223 | struct netlink_ext_ack *extack) | |
acfb50e4 VV |
224 | { |
225 | struct bnxt *bp = devlink_health_reporter_priv(reporter); | |
acfb50e4 | 226 | |
8cc95ceb EP |
227 | if (bp->fw_health->severity == SEVERITY_FATAL) |
228 | return -ENODEV; | |
229 | ||
aadb0b1a EP |
230 | set_bit(BNXT_STATE_RECOVER, &bp->state); |
231 | __bnxt_fw_recover(bp); | |
acfb50e4 | 232 | |
737d7a6c | 233 | return -EINPROGRESS; |
acfb50e4 VV |
234 | } |
235 | ||
2bb21b8d EP |
236 | static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = { |
237 | .name = "fw", | |
238 | .diagnose = bnxt_fw_diagnose, | |
188876db | 239 | .dump = bnxt_fw_dump, |
2bb21b8d | 240 | .recover = bnxt_fw_recover, |
acfb50e4 VV |
241 | }; |
242 | ||
937f188c | 243 | void bnxt_dl_fw_reporters_create(struct bnxt *bp) |
6763c779 VV |
244 | { |
245 | struct bnxt_fw_health *health = bp->fw_health; | |
246 | ||
2bb21b8d | 247 | if (!health || health->fw_reporter) |
6763c779 VV |
248 | return; |
249 | ||
2bb21b8d EP |
250 | health->fw_reporter = |
251 | devlink_health_reporter_create(bp->dl, &bnxt_dl_fw_reporter_ops, | |
ba7d16c7 | 252 | 0, bp); |
2bb21b8d EP |
253 | if (IS_ERR(health->fw_reporter)) { |
254 | netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n", | |
255 | PTR_ERR(health->fw_reporter)); | |
256 | health->fw_reporter = NULL; | |
937f188c | 257 | bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY; |
acfb50e4 | 258 | } |
6763c779 VV |
259 | } |
260 | ||
937f188c | 261 | void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all) |
6763c779 VV |
262 | { |
263 | struct bnxt_fw_health *health = bp->fw_health; | |
264 | ||
e624c70e | 265 | if (!health) |
6763c779 VV |
266 | return; |
267 | ||
937f188c VV |
268 | if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all) |
269 | return; | |
270 | ||
271 | if (health->fw_reporter) { | |
272 | devlink_health_reporter_destroy(health->fw_reporter); | |
273 | health->fw_reporter = NULL; | |
274 | } | |
657a33c8 VV |
275 | } |
276 | ||
aadb0b1a | 277 | void bnxt_devlink_health_fw_report(struct bnxt *bp) |
657a33c8 VV |
278 | { |
279 | struct bnxt_fw_health *fw_health = bp->fw_health; | |
8cc95ceb | 280 | int rc; |
657a33c8 | 281 | |
aadb0b1a | 282 | if (!fw_health) |
657a33c8 | 283 | return; |
acfb50e4 | 284 | |
2bb21b8d | 285 | if (!fw_health->fw_reporter) { |
aadb0b1a | 286 | __bnxt_fw_recover(bp); |
acfb50e4 | 287 | return; |
657a33c8 | 288 | } |
aadb0b1a | 289 | |
8cc95ceb EP |
290 | mutex_lock(&fw_health->lock); |
291 | fw_health->severity = SEVERITY_RECOVERABLE; | |
292 | fw_health->remedy = REMEDY_DEVLINK_RECOVER; | |
293 | mutex_unlock(&fw_health->lock); | |
294 | rc = devlink_health_report(fw_health->fw_reporter, "FW error reported", | |
295 | fw_health); | |
296 | if (rc == -ECANCELED) | |
297 | __bnxt_fw_recover(bp); | |
6763c779 VV |
298 | } |
299 | ||
aadb0b1a | 300 | void bnxt_dl_health_fw_status_update(struct bnxt *bp, bool healthy) |
e4e38237 | 301 | { |
8cc95ceb | 302 | struct bnxt_fw_health *fw_health = bp->fw_health; |
e4e38237 VV |
303 | u8 state; |
304 | ||
8cc95ceb EP |
305 | mutex_lock(&fw_health->lock); |
306 | if (healthy) { | |
307 | fw_health->severity = SEVERITY_NORMAL; | |
e4e38237 | 308 | state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY; |
8cc95ceb EP |
309 | } else { |
310 | fw_health->severity = SEVERITY_FATAL; | |
311 | fw_health->remedy = REMEDY_POWER_CYCLE_DEVICE; | |
e4e38237 | 312 | state = DEVLINK_HEALTH_REPORTER_STATE_ERROR; |
8cc95ceb EP |
313 | } |
314 | mutex_unlock(&fw_health->lock); | |
315 | devlink_health_reporter_state_update(fw_health->fw_reporter, state); | |
e4e38237 VV |
316 | } |
317 | ||
aadb0b1a | 318 | void bnxt_dl_health_fw_recovery_done(struct bnxt *bp) |
737d7a6c | 319 | { |
892a662f | 320 | struct bnxt_dl *dl = devlink_priv(bp->dl); |
737d7a6c | 321 | |
2bb21b8d | 322 | devlink_health_reporter_recovery_done(bp->fw_health->fw_reporter); |
892a662f | 323 | bnxt_hwrm_remote_dev_reset_set(bp, dl->remote_reset); |
737d7a6c VG |
324 | } |
325 | ||
9599e036 VV |
326 | static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, |
327 | struct netlink_ext_ack *extack); | |
328 | ||
3c415339 EP |
329 | static void |
330 | bnxt_dl_livepatch_report_err(struct bnxt *bp, struct netlink_ext_ack *extack, | |
331 | struct hwrm_fw_livepatch_output *resp) | |
332 | { | |
333 | int err = ((struct hwrm_err_output *)resp)->cmd_err; | |
334 | ||
335 | switch (err) { | |
336 | case FW_LIVEPATCH_CMD_ERR_CODE_INVALID_OPCODE: | |
337 | netdev_err(bp->dev, "Illegal live patch opcode"); | |
338 | NL_SET_ERR_MSG_MOD(extack, "Invalid opcode"); | |
339 | break; | |
340 | case FW_LIVEPATCH_CMD_ERR_CODE_NOT_SUPPORTED: | |
341 | NL_SET_ERR_MSG_MOD(extack, "Live patch operation not supported"); | |
342 | break; | |
343 | case FW_LIVEPATCH_CMD_ERR_CODE_NOT_INSTALLED: | |
344 | NL_SET_ERR_MSG_MOD(extack, "Live patch not found"); | |
345 | break; | |
346 | case FW_LIVEPATCH_CMD_ERR_CODE_NOT_PATCHED: | |
347 | NL_SET_ERR_MSG_MOD(extack, | |
348 | "Live patch deactivation failed. Firmware not patched."); | |
349 | break; | |
350 | case FW_LIVEPATCH_CMD_ERR_CODE_AUTH_FAIL: | |
351 | NL_SET_ERR_MSG_MOD(extack, "Live patch not authenticated"); | |
352 | break; | |
353 | case FW_LIVEPATCH_CMD_ERR_CODE_INVALID_HEADER: | |
354 | NL_SET_ERR_MSG_MOD(extack, "Incompatible live patch"); | |
355 | break; | |
356 | case FW_LIVEPATCH_CMD_ERR_CODE_INVALID_SIZE: | |
357 | NL_SET_ERR_MSG_MOD(extack, "Live patch has invalid size"); | |
358 | break; | |
359 | case FW_LIVEPATCH_CMD_ERR_CODE_ALREADY_PATCHED: | |
360 | NL_SET_ERR_MSG_MOD(extack, "Live patch already applied"); | |
361 | break; | |
362 | default: | |
363 | netdev_err(bp->dev, "Unexpected live patch error: %hhd\n", err); | |
364 | NL_SET_ERR_MSG_MOD(extack, "Failed to activate live patch"); | |
365 | break; | |
366 | } | |
367 | } | |
368 | ||
369 | static int | |
370 | bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack) | |
371 | { | |
372 | struct hwrm_fw_livepatch_query_output *query_resp; | |
373 | struct hwrm_fw_livepatch_query_input *query_req; | |
374 | struct hwrm_fw_livepatch_output *patch_resp; | |
375 | struct hwrm_fw_livepatch_input *patch_req; | |
376 | u32 installed = 0; | |
377 | u16 flags; | |
378 | u8 target; | |
379 | int rc; | |
380 | ||
381 | if (~bp->fw_cap & BNXT_FW_CAP_LIVEPATCH) { | |
382 | NL_SET_ERR_MSG_MOD(extack, "Device does not support live patch"); | |
383 | return -EOPNOTSUPP; | |
384 | } | |
385 | ||
386 | rc = hwrm_req_init(bp, query_req, HWRM_FW_LIVEPATCH_QUERY); | |
387 | if (rc) | |
388 | return rc; | |
389 | query_resp = hwrm_req_hold(bp, query_req); | |
390 | ||
391 | rc = hwrm_req_init(bp, patch_req, HWRM_FW_LIVEPATCH); | |
392 | if (rc) { | |
393 | hwrm_req_drop(bp, query_req); | |
394 | return rc; | |
395 | } | |
396 | patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_ACTIVATE; | |
397 | patch_req->loadtype = FW_LIVEPATCH_REQ_LOADTYPE_NVM_INSTALL; | |
398 | patch_resp = hwrm_req_hold(bp, patch_req); | |
399 | ||
400 | for (target = 1; target <= FW_LIVEPATCH_REQ_FW_TARGET_LAST; target++) { | |
401 | query_req->fw_target = target; | |
402 | rc = hwrm_req_send(bp, query_req); | |
403 | if (rc) { | |
404 | NL_SET_ERR_MSG_MOD(extack, "Failed to query packages"); | |
405 | break; | |
406 | } | |
407 | ||
408 | flags = le16_to_cpu(query_resp->status_flags); | |
409 | if (~flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL) | |
410 | continue; | |
411 | if ((flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) && | |
412 | !strncmp(query_resp->active_ver, query_resp->install_ver, | |
413 | sizeof(query_resp->active_ver))) | |
414 | continue; | |
415 | ||
416 | patch_req->fw_target = target; | |
417 | rc = hwrm_req_send(bp, patch_req); | |
418 | if (rc) { | |
419 | bnxt_dl_livepatch_report_err(bp, extack, patch_resp); | |
420 | break; | |
421 | } | |
422 | installed++; | |
423 | } | |
424 | ||
425 | if (!rc && !installed) { | |
426 | NL_SET_ERR_MSG_MOD(extack, "No live patches found"); | |
427 | rc = -ENOENT; | |
428 | } | |
429 | hwrm_req_drop(bp, query_req); | |
430 | hwrm_req_drop(bp, patch_req); | |
431 | return rc; | |
432 | } | |
433 | ||
228ea8c1 EP |
434 | static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change, |
435 | enum devlink_reload_action action, | |
436 | enum devlink_reload_limit limit, | |
437 | struct netlink_ext_ack *extack) | |
438 | { | |
439 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); | |
440 | int rc = 0; | |
441 | ||
442 | switch (action) { | |
443 | case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: { | |
46d08f55 EP |
444 | rtnl_lock(); |
445 | if (BNXT_PF(bp) && (bp->pf.active_vfs || bp->sriov_cfg)) { | |
228ea8c1 | 446 | NL_SET_ERR_MSG_MOD(extack, |
46d08f55 EP |
447 | "reload is unsupported while VFs are allocated or being configured"); |
448 | rtnl_unlock(); | |
228ea8c1 EP |
449 | return -EOPNOTSUPP; |
450 | } | |
228ea8c1 EP |
451 | if (bp->dev->reg_state == NETREG_UNREGISTERED) { |
452 | rtnl_unlock(); | |
453 | return -ENODEV; | |
454 | } | |
455 | bnxt_ulp_stop(bp); | |
456 | if (netif_running(bp->dev)) { | |
457 | rc = bnxt_close_nic(bp, true, true); | |
458 | if (rc) { | |
459 | NL_SET_ERR_MSG_MOD(extack, "Failed to close"); | |
460 | dev_close(bp->dev); | |
461 | rtnl_unlock(); | |
462 | break; | |
463 | } | |
464 | } | |
465 | bnxt_vf_reps_free(bp); | |
466 | rc = bnxt_hwrm_func_drv_unrgtr(bp); | |
467 | if (rc) { | |
468 | NL_SET_ERR_MSG_MOD(extack, "Failed to deregister"); | |
469 | if (netif_running(bp->dev)) | |
470 | dev_close(bp->dev); | |
471 | rtnl_unlock(); | |
472 | break; | |
473 | } | |
474 | bnxt_cancel_reservations(bp, false); | |
475 | bnxt_free_ctx_mem(bp); | |
476 | kfree(bp->ctx); | |
477 | bp->ctx = NULL; | |
478 | break; | |
479 | } | |
8f6c5e4d | 480 | case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: { |
3c415339 EP |
481 | if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET) |
482 | return bnxt_dl_livepatch_activate(bp, extack); | |
8f6c5e4d EP |
483 | if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET) { |
484 | NL_SET_ERR_MSG_MOD(extack, "Device not capable, requires reboot"); | |
485 | return -EOPNOTSUPP; | |
486 | } | |
892a662f EP |
487 | if (!bnxt_hwrm_reset_permitted(bp)) { |
488 | NL_SET_ERR_MSG_MOD(extack, | |
489 | "Reset denied by firmware, it may be inhibited by remote driver"); | |
490 | return -EPERM; | |
491 | } | |
8f6c5e4d EP |
492 | rtnl_lock(); |
493 | if (bp->dev->reg_state == NETREG_UNREGISTERED) { | |
494 | rtnl_unlock(); | |
495 | return -ENODEV; | |
496 | } | |
497 | if (netif_running(bp->dev)) | |
498 | set_bit(BNXT_STATE_FW_ACTIVATE, &bp->state); | |
499 | rc = bnxt_hwrm_firmware_reset(bp->dev, | |
500 | FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP, | |
501 | FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP, | |
502 | FW_RESET_REQ_FLAGS_RESET_GRACEFUL | | |
503 | FW_RESET_REQ_FLAGS_FW_ACTIVATION); | |
504 | if (rc) { | |
505 | NL_SET_ERR_MSG_MOD(extack, "Failed to activate firmware"); | |
506 | clear_bit(BNXT_STATE_FW_ACTIVATE, &bp->state); | |
507 | rtnl_unlock(); | |
508 | } | |
509 | break; | |
510 | } | |
228ea8c1 EP |
511 | default: |
512 | rc = -EOPNOTSUPP; | |
513 | } | |
514 | ||
515 | return rc; | |
516 | } | |
517 | ||
518 | static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action action, | |
519 | enum devlink_reload_limit limit, u32 *actions_performed, | |
520 | struct netlink_ext_ack *extack) | |
521 | { | |
522 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); | |
523 | int rc = 0; | |
524 | ||
525 | *actions_performed = 0; | |
526 | switch (action) { | |
527 | case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: { | |
528 | bnxt_fw_init_one(bp); | |
529 | bnxt_vf_reps_alloc(bp); | |
530 | if (netif_running(bp->dev)) | |
531 | rc = bnxt_open_nic(bp, true, true); | |
532 | bnxt_ulp_start(bp, rc); | |
533 | if (!rc) { | |
534 | bnxt_reenable_sriov(bp); | |
535 | bnxt_ptp_reapply_pps(bp); | |
536 | } | |
537 | break; | |
538 | } | |
8f6c5e4d EP |
539 | case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: { |
540 | unsigned long start = jiffies; | |
541 | unsigned long timeout = start + BNXT_DFLT_FW_RST_MAX_DSECS * HZ / 10; | |
542 | ||
3c415339 EP |
543 | if (limit == DEVLINK_RELOAD_LIMIT_NO_RESET) |
544 | break; | |
8f6c5e4d EP |
545 | if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) |
546 | timeout = start + bp->fw_health->normal_func_wait_dsecs * HZ / 10; | |
547 | if (!netif_running(bp->dev)) | |
548 | NL_SET_ERR_MSG_MOD(extack, | |
549 | "Device is closed, not waiting for reset notice that will never come"); | |
550 | rtnl_unlock(); | |
551 | while (test_bit(BNXT_STATE_FW_ACTIVATE, &bp->state)) { | |
552 | if (time_after(jiffies, timeout)) { | |
553 | NL_SET_ERR_MSG_MOD(extack, "Activation incomplete"); | |
554 | rc = -ETIMEDOUT; | |
555 | break; | |
556 | } | |
557 | if (test_bit(BNXT_STATE_ABORT_ERR, &bp->state)) { | |
558 | NL_SET_ERR_MSG_MOD(extack, "Activation aborted"); | |
559 | rc = -ENODEV; | |
560 | break; | |
561 | } | |
562 | msleep(50); | |
563 | } | |
564 | rtnl_lock(); | |
565 | if (!rc) | |
566 | *actions_performed |= BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); | |
567 | clear_bit(BNXT_STATE_FW_ACTIVATE, &bp->state); | |
568 | break; | |
569 | } | |
228ea8c1 EP |
570 | default: |
571 | return -EOPNOTSUPP; | |
572 | } | |
573 | ||
574 | if (!rc) { | |
575 | bnxt_print_device_info(bp); | |
576 | if (netif_running(bp->dev)) { | |
577 | mutex_lock(&bp->link_lock); | |
578 | bnxt_report_link(bp); | |
579 | mutex_unlock(&bp->link_lock); | |
580 | } | |
581 | *actions_performed |= BIT(action); | |
582 | } else if (netif_running(bp->dev)) { | |
583 | dev_close(bp->dev); | |
584 | } | |
585 | rtnl_unlock(); | |
586 | return rc; | |
587 | } | |
588 | ||
3c467bf3 SL |
589 | static const struct devlink_ops bnxt_dl_ops = { |
590 | #ifdef CONFIG_BNXT_SRIOV | |
591 | .eswitch_mode_set = bnxt_dl_eswitch_mode_set, | |
592 | .eswitch_mode_get = bnxt_dl_eswitch_mode_get, | |
593 | #endif /* CONFIG_BNXT_SRIOV */ | |
9599e036 | 594 | .info_get = bnxt_dl_info_get, |
d168f328 | 595 | .flash_update = bnxt_dl_flash_update, |
8f6c5e4d EP |
596 | .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | |
597 | BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), | |
3c415339 | 598 | .reload_limits = BIT(DEVLINK_RELOAD_LIMIT_NO_RESET), |
228ea8c1 EP |
599 | .reload_down = bnxt_dl_reload_down, |
600 | .reload_up = bnxt_dl_reload_up, | |
3c467bf3 SL |
601 | }; |
602 | ||
7e334fc8 VV |
603 | static const struct devlink_ops bnxt_vf_dl_ops; |
604 | ||
2dc0865e VV |
605 | enum bnxt_dl_param_id { |
606 | BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, | |
607 | BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, | |
608 | }; | |
609 | ||
6354b95e VV |
610 | static const struct bnxt_dl_nvm_param nvm_params[] = { |
611 | {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV, | |
c329230c | 612 | BNXT_NVM_SHARED_CFG, 1, 1}, |
7d859234 | 613 | {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI, |
c329230c | 614 | BNXT_NVM_SHARED_CFG, 1, 1}, |
f399e849 | 615 | {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, |
c329230c | 616 | NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4}, |
f399e849 | 617 | {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, |
c329230c | 618 | NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4}, |
2dc0865e | 619 | {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK, |
c329230c | 620 | BNXT_NVM_SHARED_CFG, 1, 1}, |
6354b95e VV |
621 | }; |
622 | ||
83a46a82 MC |
623 | union bnxt_nvm_data { |
624 | u8 val8; | |
625 | __le32 val32; | |
626 | }; | |
627 | ||
628 | static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst, | |
629 | union devlink_param_value *src, | |
630 | int nvm_num_bits, int dl_num_bytes) | |
631 | { | |
632 | u32 val32 = 0; | |
633 | ||
634 | if (nvm_num_bits == 1) { | |
635 | dst->val8 = src->vbool; | |
636 | return; | |
637 | } | |
638 | if (dl_num_bytes == 4) | |
639 | val32 = src->vu32; | |
640 | else if (dl_num_bytes == 2) | |
641 | val32 = (u32)src->vu16; | |
642 | else if (dl_num_bytes == 1) | |
643 | val32 = (u32)src->vu8; | |
644 | dst->val32 = cpu_to_le32(val32); | |
645 | } | |
646 | ||
647 | static void bnxt_copy_from_nvm_data(union devlink_param_value *dst, | |
648 | union bnxt_nvm_data *src, | |
649 | int nvm_num_bits, int dl_num_bytes) | |
650 | { | |
651 | u32 val32; | |
652 | ||
653 | if (nvm_num_bits == 1) { | |
654 | dst->vbool = src->val8; | |
655 | return; | |
656 | } | |
657 | val32 = le32_to_cpu(src->val32); | |
658 | if (dl_num_bytes == 4) | |
659 | dst->vu32 = val32; | |
660 | else if (dl_num_bytes == 2) | |
661 | dst->vu16 = (u16)val32; | |
662 | else if (dl_num_bytes == 1) | |
663 | dst->vu8 = (u8)val32; | |
664 | } | |
665 | ||
beb55fcf | 666 | static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver) |
9599e036 | 667 | { |
bbf33d1d | 668 | struct hwrm_nvm_get_variable_input *req; |
beb55fcf EP |
669 | u16 bytes = BNXT_NVM_CFG_VER_BYTES; |
670 | u16 bits = BNXT_NVM_CFG_VER_BITS; | |
671 | union devlink_param_value ver; | |
9599e036 VV |
672 | union bnxt_nvm_data *data; |
673 | dma_addr_t data_dma_addr; | |
beb55fcf EP |
674 | int rc, i = 2; |
675 | u16 dim = 1; | |
9599e036 | 676 | |
bbf33d1d EP |
677 | rc = hwrm_req_init(bp, req, HWRM_NVM_GET_VARIABLE); |
678 | if (rc) | |
679 | return rc; | |
680 | ||
681 | data = hwrm_req_dma_slice(bp, req, sizeof(*data), &data_dma_addr); | |
682 | if (!data) { | |
683 | rc = -ENOMEM; | |
684 | goto exit; | |
685 | } | |
9599e036 | 686 | |
beb55fcf EP |
687 | /* earlier devices present as an array of raw bytes */ |
688 | if (!BNXT_CHIP_P5(bp)) { | |
689 | dim = 0; | |
690 | i = 0; | |
691 | bits *= 3; /* array of 3 version components */ | |
692 | bytes *= 4; /* copy whole word */ | |
693 | } | |
694 | ||
bbf33d1d EP |
695 | hwrm_req_hold(bp, req); |
696 | req->dest_data_addr = cpu_to_le64(data_dma_addr); | |
beb55fcf | 697 | req->data_len = cpu_to_le16(bits); |
bbf33d1d | 698 | req->option_num = cpu_to_le16(NVM_OFF_NVM_CFG_VER); |
beb55fcf | 699 | req->dimensions = cpu_to_le16(dim); |
9599e036 | 700 | |
beb55fcf EP |
701 | while (i >= 0) { |
702 | req->index_0 = cpu_to_le16(i--); | |
703 | rc = hwrm_req_send_silent(bp, req); | |
704 | if (rc) | |
705 | goto exit; | |
706 | bnxt_copy_from_nvm_data(&ver, data, bits, bytes); | |
707 | ||
708 | if (BNXT_CHIP_P5(bp)) { | |
709 | *nvm_cfg_ver <<= 8; | |
710 | *nvm_cfg_ver |= ver.vu8; | |
711 | } else { | |
712 | *nvm_cfg_ver = ver.vu32; | |
713 | } | |
714 | } | |
9599e036 | 715 | |
bbf33d1d EP |
716 | exit: |
717 | hwrm_req_drop(bp, req); | |
9599e036 VV |
718 | return rc; |
719 | } | |
720 | ||
7154917a VV |
721 | static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req, |
722 | enum bnxt_dl_version_type type, const char *key, | |
723 | char *buf) | |
724 | { | |
725 | if (!strlen(buf)) | |
726 | return 0; | |
727 | ||
728 | if ((bp->flags & BNXT_FLAG_CHIP_P5) && | |
729 | (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) || | |
730 | !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE))) | |
731 | return 0; | |
732 | ||
733 | switch (type) { | |
734 | case BNXT_VERSION_FIXED: | |
735 | return devlink_info_version_fixed_put(req, key, buf); | |
736 | case BNXT_VERSION_RUNNING: | |
737 | return devlink_info_version_running_put(req, key, buf); | |
738 | case BNXT_VERSION_STORED: | |
739 | return devlink_info_version_stored_put(req, key, buf); | |
740 | } | |
741 | return 0; | |
742 | } | |
743 | ||
3c415339 EP |
744 | #define BNXT_FW_SRT_PATCH "fw.srt.patch" |
745 | #define BNXT_FW_CRT_PATCH "fw.crt.patch" | |
746 | ||
747 | static int bnxt_dl_livepatch_info_put(struct bnxt *bp, | |
748 | struct devlink_info_req *req, | |
749 | const char *key) | |
750 | { | |
751 | struct hwrm_fw_livepatch_query_input *query; | |
752 | struct hwrm_fw_livepatch_query_output *resp; | |
753 | u16 flags; | |
754 | int rc; | |
755 | ||
756 | if (~bp->fw_cap & BNXT_FW_CAP_LIVEPATCH) | |
757 | return 0; | |
758 | ||
759 | rc = hwrm_req_init(bp, query, HWRM_FW_LIVEPATCH_QUERY); | |
760 | if (rc) | |
761 | return rc; | |
762 | ||
763 | if (!strcmp(key, BNXT_FW_SRT_PATCH)) | |
764 | query->fw_target = FW_LIVEPATCH_QUERY_REQ_FW_TARGET_SECURE_FW; | |
765 | else if (!strcmp(key, BNXT_FW_CRT_PATCH)) | |
766 | query->fw_target = FW_LIVEPATCH_QUERY_REQ_FW_TARGET_COMMON_FW; | |
767 | else | |
768 | goto exit; | |
769 | ||
770 | resp = hwrm_req_hold(bp, query); | |
771 | rc = hwrm_req_send(bp, query); | |
772 | if (rc) | |
773 | goto exit; | |
774 | ||
775 | flags = le16_to_cpu(resp->status_flags); | |
776 | if (flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) { | |
777 | resp->active_ver[sizeof(resp->active_ver) - 1] = '\0'; | |
778 | rc = devlink_info_version_running_put(req, key, resp->active_ver); | |
779 | if (rc) | |
780 | goto exit; | |
781 | } | |
782 | ||
783 | if (flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL) { | |
784 | resp->install_ver[sizeof(resp->install_ver) - 1] = '\0'; | |
785 | rc = devlink_info_version_stored_put(req, key, resp->install_ver); | |
786 | if (rc) | |
787 | goto exit; | |
788 | } | |
789 | ||
790 | exit: | |
791 | hwrm_req_drop(bp, query); | |
792 | return rc; | |
793 | } | |
794 | ||
7154917a VV |
795 | #define HWRM_FW_VER_STR_LEN 16 |
796 | ||
9599e036 VV |
797 | static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, |
798 | struct netlink_ext_ack *extack) | |
799 | { | |
1388875b | 800 | struct hwrm_nvm_get_dev_info_output nvm_dev_info; |
9599e036 | 801 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); |
9599e036 VV |
802 | struct hwrm_ver_get_output *ver_resp; |
803 | char mgmt_ver[FW_VER_STR_LEN]; | |
804 | char roce_ver[FW_VER_STR_LEN]; | |
7154917a | 805 | char ncsi_ver[FW_VER_STR_LEN]; |
9599e036 | 806 | char buf[32]; |
beb55fcf | 807 | u32 ver = 0; |
9599e036 VV |
808 | int rc; |
809 | ||
810 | rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME); | |
811 | if (rc) | |
812 | return rc; | |
813 | ||
7154917a VV |
814 | if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) { |
815 | sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", | |
816 | bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4], | |
817 | bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]); | |
818 | rc = devlink_info_serial_number_put(req, buf); | |
56d69c78 VV |
819 | if (rc) |
820 | return rc; | |
821 | } | |
822 | ||
9bf88b9f VV |
823 | if (strlen(bp->board_serialno)) { |
824 | rc = devlink_info_board_serial_number_put(req, bp->board_serialno); | |
825 | if (rc) | |
826 | return rc; | |
827 | } | |
828 | ||
7154917a VV |
829 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED, |
830 | DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, | |
831 | bp->board_partno); | |
832 | if (rc) | |
833 | return rc; | |
834 | ||
9599e036 | 835 | sprintf(buf, "%X", bp->chip_num); |
7154917a VV |
836 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED, |
837 | DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf); | |
9599e036 VV |
838 | if (rc) |
839 | return rc; | |
840 | ||
841 | ver_resp = &bp->ver_resp; | |
6fdab8a3 | 842 | sprintf(buf, "%c%d", 'A' + ver_resp->chip_rev, ver_resp->chip_metal); |
7154917a VV |
843 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED, |
844 | DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf); | |
9599e036 VV |
845 | if (rc) |
846 | return rc; | |
847 | ||
1388875b VV |
848 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, |
849 | DEVLINK_INFO_VERSION_GENERIC_FW_PSID, | |
850 | bp->nvm_cfg_ver); | |
851 | if (rc) | |
852 | return rc; | |
853 | ||
7154917a VV |
854 | buf[0] = 0; |
855 | strncat(buf, ver_resp->active_pkg_name, HWRM_FW_VER_STR_LEN); | |
856 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, | |
857 | DEVLINK_INFO_VERSION_GENERIC_FW, buf); | |
858 | if (rc) | |
859 | return rc; | |
9599e036 | 860 | |
beb55fcf | 861 | if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &ver)) { |
1656db67 EP |
862 | sprintf(buf, "%d.%d.%d", (ver >> 16) & 0xff, (ver >> 8) & 0xff, |
863 | ver & 0xff); | |
1388875b | 864 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, |
7154917a VV |
865 | DEVLINK_INFO_VERSION_GENERIC_FW_PSID, |
866 | buf); | |
9599e036 VV |
867 | if (rc) |
868 | return rc; | |
869 | } | |
870 | ||
871 | if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) { | |
7154917a | 872 | snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", |
9599e036 VV |
873 | ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor, |
874 | ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch); | |
875 | ||
7154917a | 876 | snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", |
9599e036 VV |
877 | ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor, |
878 | ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch); | |
879 | ||
880 | snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", | |
881 | ver_resp->roce_fw_major, ver_resp->roce_fw_minor, | |
882 | ver_resp->roce_fw_build, ver_resp->roce_fw_patch); | |
883 | } else { | |
7154917a | 884 | snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", |
9599e036 VV |
885 | ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b, |
886 | ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b); | |
887 | ||
7154917a | 888 | snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", |
9599e036 VV |
889 | ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b, |
890 | ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b); | |
891 | ||
892 | snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", | |
893 | ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b, | |
894 | ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b); | |
895 | } | |
7154917a VV |
896 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, |
897 | DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver); | |
9599e036 VV |
898 | if (rc) |
899 | return rc; | |
900 | ||
7154917a VV |
901 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, |
902 | DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API, | |
903 | bp->hwrm_ver_supp); | |
b7a444f0 VV |
904 | if (rc) |
905 | return rc; | |
906 | ||
7154917a VV |
907 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, |
908 | DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver); | |
909 | if (rc) | |
910 | return rc; | |
9599e036 | 911 | |
1388875b VV |
912 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, |
913 | DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); | |
914 | if (rc) | |
915 | return rc; | |
916 | ||
917 | rc = bnxt_hwrm_nvm_get_dev_info(bp, &nvm_dev_info); | |
918 | if (rc || | |
63185eb3 VG |
919 | !(nvm_dev_info.flags & NVM_GET_DEV_INFO_RESP_FLAGS_FW_VER_VALID)) { |
920 | if (!bnxt_get_pkginfo(bp->dev, buf, sizeof(buf))) | |
921 | return bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, | |
922 | DEVLINK_INFO_VERSION_GENERIC_FW, | |
923 | buf); | |
1388875b | 924 | return 0; |
63185eb3 | 925 | } |
1388875b VV |
926 | |
927 | buf[0] = 0; | |
928 | strncat(buf, nvm_dev_info.pkg_name, HWRM_FW_VER_STR_LEN); | |
929 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, | |
930 | DEVLINK_INFO_VERSION_GENERIC_FW, buf); | |
931 | if (rc) | |
932 | return rc; | |
933 | ||
934 | snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", | |
935 | nvm_dev_info.hwrm_fw_major, nvm_dev_info.hwrm_fw_minor, | |
936 | nvm_dev_info.hwrm_fw_build, nvm_dev_info.hwrm_fw_patch); | |
937 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, | |
938 | DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver); | |
939 | if (rc) | |
940 | return rc; | |
941 | ||
942 | snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", | |
943 | nvm_dev_info.mgmt_fw_major, nvm_dev_info.mgmt_fw_minor, | |
944 | nvm_dev_info.mgmt_fw_build, nvm_dev_info.mgmt_fw_patch); | |
945 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, | |
946 | DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver); | |
947 | if (rc) | |
948 | return rc; | |
949 | ||
950 | snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", | |
951 | nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor, | |
952 | nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch); | |
3c415339 EP |
953 | rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, |
954 | DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); | |
955 | if (rc) | |
956 | return rc; | |
957 | ||
958 | rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH); | |
959 | if (rc) | |
960 | return rc; | |
961 | return bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_CRT_PATCH); | |
962 | ||
9599e036 VV |
963 | } |
964 | ||
6354b95e | 965 | static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, |
bbf33d1d | 966 | union devlink_param_value *val) |
6354b95e | 967 | { |
6fc92c33 | 968 | struct hwrm_nvm_get_variable_input *req = msg; |
6354b95e | 969 | struct bnxt_dl_nvm_param nvm_param; |
bbf33d1d | 970 | struct hwrm_err_output *resp; |
83a46a82 | 971 | union bnxt_nvm_data *data; |
6354b95e | 972 | dma_addr_t data_dma_addr; |
c329230c | 973 | int idx = 0, rc, i; |
6354b95e VV |
974 | |
975 | /* Get/Set NVM CFG parameter is supported only on PFs */ | |
bbf33d1d EP |
976 | if (BNXT_VF(bp)) { |
977 | hwrm_req_drop(bp, req); | |
6354b95e | 978 | return -EPERM; |
bbf33d1d | 979 | } |
6354b95e VV |
980 | |
981 | for (i = 0; i < ARRAY_SIZE(nvm_params); i++) { | |
982 | if (nvm_params[i].id == param_id) { | |
983 | nvm_param = nvm_params[i]; | |
984 | break; | |
985 | } | |
986 | } | |
987 | ||
bbf33d1d EP |
988 | if (i == ARRAY_SIZE(nvm_params)) { |
989 | hwrm_req_drop(bp, req); | |
65fac4fe | 990 | return -EOPNOTSUPP; |
bbf33d1d | 991 | } |
65fac4fe | 992 | |
6354b95e VV |
993 | if (nvm_param.dir_type == BNXT_NVM_PORT_CFG) |
994 | idx = bp->pf.port_id; | |
995 | else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG) | |
996 | idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID; | |
997 | ||
bbf33d1d EP |
998 | data = hwrm_req_dma_slice(bp, req, sizeof(*data), &data_dma_addr); |
999 | ||
1000 | if (!data) { | |
1001 | hwrm_req_drop(bp, req); | |
6354b95e | 1002 | return -ENOMEM; |
bbf33d1d | 1003 | } |
6354b95e | 1004 | |
6fc92c33 | 1005 | req->dest_data_addr = cpu_to_le64(data_dma_addr); |
c329230c | 1006 | req->data_len = cpu_to_le16(nvm_param.nvm_num_bits); |
6354b95e VV |
1007 | req->option_num = cpu_to_le16(nvm_param.offset); |
1008 | req->index_0 = cpu_to_le16(idx); | |
1009 | if (idx) | |
1010 | req->dimensions = cpu_to_le16(1); | |
1011 | ||
bbf33d1d | 1012 | resp = hwrm_req_hold(bp, req); |
b703ba75 | 1013 | if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) { |
83a46a82 MC |
1014 | bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits, |
1015 | nvm_param.dl_num_bytes); | |
bbf33d1d | 1016 | rc = hwrm_req_send(bp, msg); |
b703ba75 | 1017 | } else { |
bbf33d1d | 1018 | rc = hwrm_req_send_silent(bp, msg); |
05069dd4 | 1019 | if (!rc) { |
83a46a82 MC |
1020 | bnxt_copy_from_nvm_data(val, data, |
1021 | nvm_param.nvm_num_bits, | |
1022 | nvm_param.dl_num_bytes); | |
05069dd4 | 1023 | } else { |
05069dd4 VV |
1024 | if (resp->cmd_err == |
1025 | NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST) | |
1026 | rc = -EOPNOTSUPP; | |
1027 | } | |
b703ba75 | 1028 | } |
bbf33d1d | 1029 | hwrm_req_drop(bp, req); |
d4f1420d | 1030 | if (rc == -EACCES) |
3a1d52a5 | 1031 | netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n"); |
d4f1420d | 1032 | return rc; |
6354b95e VV |
1033 | } |
1034 | ||
1035 | static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id, | |
1036 | struct devlink_param_gset_ctx *ctx) | |
1037 | { | |
6354b95e | 1038 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); |
bbf33d1d | 1039 | struct hwrm_nvm_get_variable_input *req; |
2dc0865e | 1040 | int rc; |
6354b95e | 1041 | |
bbf33d1d EP |
1042 | rc = hwrm_req_init(bp, req, HWRM_NVM_GET_VARIABLE); |
1043 | if (rc) | |
1044 | return rc; | |
1045 | ||
1046 | rc = bnxt_hwrm_nvm_req(bp, id, req, &ctx->val); | |
1047 | if (!rc && id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) | |
1048 | ctx->val.vbool = !ctx->val.vbool; | |
2dc0865e VV |
1049 | |
1050 | return rc; | |
6354b95e VV |
1051 | } |
1052 | ||
1053 | static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id, | |
1054 | struct devlink_param_gset_ctx *ctx) | |
1055 | { | |
6354b95e | 1056 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); |
bbf33d1d EP |
1057 | struct hwrm_nvm_set_variable_input *req; |
1058 | int rc; | |
6354b95e | 1059 | |
bbf33d1d EP |
1060 | rc = hwrm_req_init(bp, req, HWRM_NVM_SET_VARIABLE); |
1061 | if (rc) | |
1062 | return rc; | |
2dc0865e VV |
1063 | |
1064 | if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) | |
1065 | ctx->val.vbool = !ctx->val.vbool; | |
1066 | ||
bbf33d1d | 1067 | return bnxt_hwrm_nvm_req(bp, id, req, &ctx->val); |
6354b95e VV |
1068 | } |
1069 | ||
f399e849 VV |
1070 | static int bnxt_dl_msix_validate(struct devlink *dl, u32 id, |
1071 | union devlink_param_value val, | |
1072 | struct netlink_ext_ack *extack) | |
1073 | { | |
5fc7c12f | 1074 | int max_val = -1; |
f399e849 VV |
1075 | |
1076 | if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX) | |
1077 | max_val = BNXT_MSIX_VEC_MAX; | |
1078 | ||
1079 | if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN) | |
1080 | max_val = BNXT_MSIX_VEC_MIN_MAX; | |
1081 | ||
5fc7c12f | 1082 | if (val.vu32 > max_val) { |
f399e849 VV |
1083 | NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range"); |
1084 | return -EINVAL; | |
1085 | } | |
1086 | ||
1087 | return 0; | |
1088 | } | |
1089 | ||
892a662f EP |
1090 | static int bnxt_remote_dev_reset_get(struct devlink *dl, u32 id, |
1091 | struct devlink_param_gset_ctx *ctx) | |
1092 | { | |
1093 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); | |
1094 | ||
1095 | if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF) | |
1096 | return -EOPNOTSUPP; | |
1097 | ||
1098 | ctx->val.vbool = bnxt_dl_get_remote_reset(dl); | |
1099 | return 0; | |
1100 | } | |
1101 | ||
1102 | static int bnxt_remote_dev_reset_set(struct devlink *dl, u32 id, | |
1103 | struct devlink_param_gset_ctx *ctx) | |
1104 | { | |
1105 | struct bnxt *bp = bnxt_get_bp_from_dl(dl); | |
1106 | int rc; | |
1107 | ||
1108 | rc = bnxt_hwrm_remote_dev_reset_set(bp, ctx->val.vbool); | |
1109 | if (rc) | |
1110 | return rc; | |
1111 | ||
1112 | bnxt_dl_set_remote_reset(dl, ctx->val.vbool); | |
1113 | return rc; | |
1114 | } | |
1115 | ||
6354b95e VV |
1116 | static const struct devlink_param bnxt_dl_params[] = { |
1117 | DEVLINK_PARAM_GENERIC(ENABLE_SRIOV, | |
1118 | BIT(DEVLINK_PARAM_CMODE_PERMANENT), | |
1119 | bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, | |
1120 | NULL), | |
7d859234 VV |
1121 | DEVLINK_PARAM_GENERIC(IGNORE_ARI, |
1122 | BIT(DEVLINK_PARAM_CMODE_PERMANENT), | |
1123 | bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, | |
1124 | NULL), | |
f399e849 VV |
1125 | DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX, |
1126 | BIT(DEVLINK_PARAM_CMODE_PERMANENT), | |
1127 | bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, | |
1128 | bnxt_dl_msix_validate), | |
1129 | DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN, | |
1130 | BIT(DEVLINK_PARAM_CMODE_PERMANENT), | |
1131 | bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, | |
1132 | bnxt_dl_msix_validate), | |
2dc0865e VV |
1133 | DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, |
1134 | "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL, | |
1135 | BIT(DEVLINK_PARAM_CMODE_PERMANENT), | |
1136 | bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, | |
1137 | NULL), | |
892a662f EP |
1138 | /* keep REMOTE_DEV_RESET last, it is excluded based on caps */ |
1139 | DEVLINK_PARAM_GENERIC(ENABLE_REMOTE_DEV_RESET, | |
1140 | BIT(DEVLINK_PARAM_CMODE_RUNTIME), | |
1141 | bnxt_remote_dev_reset_get, | |
1142 | bnxt_remote_dev_reset_set, NULL), | |
6354b95e VV |
1143 | }; |
1144 | ||
d6292ade VV |
1145 | static int bnxt_dl_params_register(struct bnxt *bp) |
1146 | { | |
892a662f | 1147 | int num_params = ARRAY_SIZE(bnxt_dl_params); |
d6292ade VV |
1148 | int rc; |
1149 | ||
002870eb VV |
1150 | if (bp->hwrm_spec_code < 0x10600) |
1151 | return 0; | |
1152 | ||
892a662f EP |
1153 | if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF) |
1154 | num_params--; | |
1155 | ||
1156 | rc = devlink_params_register(bp->dl, bnxt_dl_params, num_params); | |
5df290e7 | 1157 | if (rc) |
9a005c38 | 1158 | netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n", |
d6292ade | 1159 | rc); |
5df290e7 | 1160 | return rc; |
d6292ade VV |
1161 | } |
1162 | ||
1163 | static void bnxt_dl_params_unregister(struct bnxt *bp) | |
1164 | { | |
892a662f EP |
1165 | int num_params = ARRAY_SIZE(bnxt_dl_params); |
1166 | ||
002870eb VV |
1167 | if (bp->hwrm_spec_code < 0x10600) |
1168 | return; | |
1169 | ||
892a662f EP |
1170 | if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF) |
1171 | num_params--; | |
1172 | ||
1173 | devlink_params_unregister(bp->dl, bnxt_dl_params, num_params); | |
d6292ade VV |
1174 | } |
1175 | ||
3c467bf3 SL |
1176 | int bnxt_dl_register(struct bnxt *bp) |
1177 | { | |
919d13a7 | 1178 | const struct devlink_ops *devlink_ops; |
71ad8d55 | 1179 | struct devlink_port_attrs attrs = {}; |
e624c70e | 1180 | struct bnxt_dl *bp_dl; |
3c467bf3 SL |
1181 | struct devlink *dl; |
1182 | int rc; | |
1183 | ||
7e334fc8 | 1184 | if (BNXT_PF(bp)) |
919d13a7 | 1185 | devlink_ops = &bnxt_dl_ops; |
7e334fc8 | 1186 | else |
919d13a7 LR |
1187 | devlink_ops = &bnxt_vf_dl_ops; |
1188 | ||
1189 | dl = devlink_alloc(devlink_ops, sizeof(struct bnxt_dl), &bp->pdev->dev); | |
3c467bf3 | 1190 | if (!dl) { |
9a005c38 | 1191 | netdev_warn(bp->dev, "devlink_alloc failed\n"); |
3c467bf3 SL |
1192 | return -ENOMEM; |
1193 | } | |
1194 | ||
e624c70e LR |
1195 | bp->dl = dl; |
1196 | bp_dl = devlink_priv(dl); | |
1197 | bp_dl->bp = bp; | |
892a662f | 1198 | bnxt_dl_set_remote_reset(dl, true); |
6354b95e VV |
1199 | |
1200 | /* Add switchdev eswitch mode setting, if SRIOV supported */ | |
1201 | if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) && | |
1202 | bp->hwrm_spec_code > 0x10803) | |
1203 | bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; | |
1204 | ||
7e334fc8 | 1205 | if (!BNXT_PF(bp)) |
5df290e7 | 1206 | goto out; |
7e334fc8 | 1207 | |
71ad8d55 DR |
1208 | attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; |
1209 | attrs.phys.port_number = bp->pf.port_id; | |
1210 | memcpy(attrs.switch_id.id, bp->dsn, sizeof(bp->dsn)); | |
1211 | attrs.switch_id.id_len = sizeof(bp->dsn); | |
1212 | devlink_port_attrs_set(&bp->dl_port, &attrs); | |
782a624d VV |
1213 | rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id); |
1214 | if (rc) { | |
9a005c38 | 1215 | netdev_err(bp->dev, "devlink_port_register failed\n"); |
db4278c5 | 1216 | goto err_dl_free; |
782a624d | 1217 | } |
782a624d | 1218 | |
d6292ade VV |
1219 | rc = bnxt_dl_params_register(bp); |
1220 | if (rc) | |
782a624d | 1221 | goto err_dl_port_unreg; |
7c62cfb8 | 1222 | |
5df290e7 LR |
1223 | out: |
1224 | devlink_register(dl); | |
3c467bf3 | 1225 | return 0; |
6354b95e | 1226 | |
782a624d VV |
1227 | err_dl_port_unreg: |
1228 | devlink_port_unregister(&bp->dl_port); | |
6354b95e | 1229 | err_dl_free: |
6354b95e VV |
1230 | devlink_free(dl); |
1231 | return rc; | |
3c467bf3 SL |
1232 | } |
1233 | ||
1234 | void bnxt_dl_unregister(struct bnxt *bp) | |
1235 | { | |
1236 | struct devlink *dl = bp->dl; | |
1237 | ||
5df290e7 | 1238 | devlink_unregister(dl); |
7e334fc8 | 1239 | if (BNXT_PF(bp)) { |
d6292ade | 1240 | bnxt_dl_params_unregister(bp); |
7e334fc8 | 1241 | devlink_port_unregister(&bp->dl_port); |
7e334fc8 | 1242 | } |
3c467bf3 SL |
1243 | devlink_free(dl); |
1244 | } |