Commit | Line | Data |
---|---|---|
1adf7ead JK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2020, Intel Corporation. */ | |
3 | ||
4 | #include "ice.h" | |
ff2e5c70 | 5 | #include "ice_lib.h" |
1adf7ead | 6 | #include "ice_devlink.h" |
3ea9bd5d | 7 | #include "ice_eswitch.h" |
d69ea414 | 8 | #include "ice_fw_update.h" |
1adf7ead | 9 | |
74789085 JK |
10 | /* context for devlink info version reporting */ |
11 | struct ice_info_ctx { | |
12 | char buf[128]; | |
e67fbcfb | 13 | struct ice_orom_info pending_orom; |
2c4fe41d | 14 | struct ice_nvm_info pending_nvm; |
e120a9ab | 15 | struct ice_netlist_info pending_netlist; |
2c4fe41d | 16 | struct ice_hw_dev_caps dev_caps; |
74789085 JK |
17 | }; |
18 | ||
19 | /* The following functions are used to format specific strings for various | |
20 | * devlink info versions. The ctx parameter is used to provide the storage | |
21 | * buffer, as well as any ancillary information calculated when the info | |
22 | * request was made. | |
23 | * | |
24 | * If a version does not exist, for example when attempting to get the | |
25 | * inactive version of flash when there is no pending update, the function | |
0128cc6e | 26 | * should leave the buffer in the ctx structure empty. |
74789085 JK |
27 | */ |
28 | ||
29 | static void ice_info_get_dsn(struct ice_pf *pf, struct ice_info_ctx *ctx) | |
ff2e5c70 JK |
30 | { |
31 | u8 dsn[8]; | |
32 | ||
33 | /* Copy the DSN into an array in Big Endian format */ | |
34 | put_unaligned_be64(pci_get_dsn(pf->pdev), dsn); | |
35 | ||
74789085 | 36 | snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn); |
ff2e5c70 JK |
37 | } |
38 | ||
0128cc6e | 39 | static void ice_info_pba(struct ice_pf *pf, struct ice_info_ctx *ctx) |
e961b679 JK |
40 | { |
41 | struct ice_hw *hw = &pf->hw; | |
5e24d598 | 42 | int status; |
e961b679 | 43 | |
74789085 | 44 | status = ice_read_pba_string(hw, (u8 *)ctx->buf, sizeof(ctx->buf)); |
e961b679 | 45 | if (status) |
a8f89fa2 | 46 | /* We failed to locate the PBA, so just skip this entry */ |
5f87ec48 TN |
47 | dev_dbg(ice_pf_to_dev(pf), "Failed to read Product Board Assembly string, status %d\n", |
48 | status); | |
e961b679 JK |
49 | } |
50 | ||
0128cc6e | 51 | static void ice_info_fw_mgmt(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 JK |
52 | { |
53 | struct ice_hw *hw = &pf->hw; | |
54 | ||
0128cc6e JK |
55 | snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", |
56 | hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch); | |
ff2e5c70 JK |
57 | } |
58 | ||
0128cc6e | 59 | static void ice_info_fw_api(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 JK |
60 | { |
61 | struct ice_hw *hw = &pf->hw; | |
62 | ||
b726ddf9 BC |
63 | snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", hw->api_maj_ver, |
64 | hw->api_min_ver, hw->api_patch); | |
ff2e5c70 JK |
65 | } |
66 | ||
0128cc6e | 67 | static void ice_info_fw_build(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 JK |
68 | { |
69 | struct ice_hw *hw = &pf->hw; | |
70 | ||
74789085 | 71 | snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build); |
ff2e5c70 JK |
72 | } |
73 | ||
0128cc6e | 74 | static void ice_info_orom_ver(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 | 75 | { |
9af368fa | 76 | struct ice_orom_info *orom = &pf->hw.flash.orom; |
ff2e5c70 | 77 | |
0128cc6e JK |
78 | snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", |
79 | orom->major, orom->build, orom->patch); | |
ff2e5c70 JK |
80 | } |
81 | ||
0128cc6e JK |
82 | static void |
83 | ice_info_pending_orom_ver(struct ice_pf __always_unused *pf, | |
84 | struct ice_info_ctx *ctx) | |
e67fbcfb JK |
85 | { |
86 | struct ice_orom_info *orom = &ctx->pending_orom; | |
87 | ||
88 | if (ctx->dev_caps.common_cap.nvm_update_pending_orom) | |
89 | snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", | |
90 | orom->major, orom->build, orom->patch); | |
e67fbcfb JK |
91 | } |
92 | ||
0128cc6e | 93 | static void ice_info_nvm_ver(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 | 94 | { |
9af368fa | 95 | struct ice_nvm_info *nvm = &pf->hw.flash.nvm; |
ff2e5c70 | 96 | |
74789085 | 97 | snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor); |
ff2e5c70 JK |
98 | } |
99 | ||
0128cc6e JK |
100 | static void |
101 | ice_info_pending_nvm_ver(struct ice_pf __always_unused *pf, | |
102 | struct ice_info_ctx *ctx) | |
2c4fe41d JK |
103 | { |
104 | struct ice_nvm_info *nvm = &ctx->pending_nvm; | |
105 | ||
106 | if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) | |
0128cc6e JK |
107 | snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", |
108 | nvm->major, nvm->minor); | |
2c4fe41d JK |
109 | } |
110 | ||
0128cc6e | 111 | static void ice_info_eetrack(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 | 112 | { |
9af368fa | 113 | struct ice_nvm_info *nvm = &pf->hw.flash.nvm; |
ff2e5c70 | 114 | |
74789085 | 115 | snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm->eetrack); |
ff2e5c70 JK |
116 | } |
117 | ||
0128cc6e JK |
118 | static void |
119 | ice_info_pending_eetrack(struct ice_pf *pf, struct ice_info_ctx *ctx) | |
2c4fe41d JK |
120 | { |
121 | struct ice_nvm_info *nvm = &ctx->pending_nvm; | |
122 | ||
123 | if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) | |
124 | snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm->eetrack); | |
2c4fe41d JK |
125 | } |
126 | ||
0128cc6e | 127 | static void ice_info_ddp_pkg_name(struct ice_pf *pf, struct ice_info_ctx *ctx) |
ff2e5c70 JK |
128 | { |
129 | struct ice_hw *hw = &pf->hw; | |
130 | ||
74789085 | 131 | snprintf(ctx->buf, sizeof(ctx->buf), "%s", hw->active_pkg_name); |
ff2e5c70 JK |
132 | } |
133 | ||
0128cc6e JK |
134 | static void |
135 | ice_info_ddp_pkg_version(struct ice_pf *pf, struct ice_info_ctx *ctx) | |
ff2e5c70 JK |
136 | { |
137 | struct ice_pkg_ver *pkg = &pf->hw.active_pkg_ver; | |
138 | ||
0128cc6e JK |
139 | snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u.%u", |
140 | pkg->major, pkg->minor, pkg->update, pkg->draft); | |
ff2e5c70 JK |
141 | } |
142 | ||
0128cc6e JK |
143 | static void |
144 | ice_info_ddp_pkg_bundle_id(struct ice_pf *pf, struct ice_info_ctx *ctx) | |
410d0687 | 145 | { |
74789085 | 146 | snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", pf->hw.active_track_id); |
410d0687 JK |
147 | } |
148 | ||
0128cc6e | 149 | static void ice_info_netlist_ver(struct ice_pf *pf, struct ice_info_ctx *ctx) |
f45a645f | 150 | { |
9af368fa | 151 | struct ice_netlist_info *netlist = &pf->hw.flash.netlist; |
f45a645f JK |
152 | |
153 | /* The netlist version fields are BCD formatted */ | |
0128cc6e JK |
154 | snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x", |
155 | netlist->major, netlist->minor, | |
156 | netlist->type >> 16, netlist->type & 0xFFFF, | |
157 | netlist->rev, netlist->cust_ver); | |
f45a645f JK |
158 | } |
159 | ||
0128cc6e | 160 | static void ice_info_netlist_build(struct ice_pf *pf, struct ice_info_ctx *ctx) |
f45a645f | 161 | { |
9af368fa | 162 | struct ice_netlist_info *netlist = &pf->hw.flash.netlist; |
f45a645f | 163 | |
74789085 | 164 | snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash); |
f45a645f JK |
165 | } |
166 | ||
0128cc6e JK |
167 | static void |
168 | ice_info_pending_netlist_ver(struct ice_pf __always_unused *pf, | |
169 | struct ice_info_ctx *ctx) | |
e120a9ab JK |
170 | { |
171 | struct ice_netlist_info *netlist = &ctx->pending_netlist; | |
172 | ||
173 | /* The netlist version fields are BCD formatted */ | |
174 | if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) | |
175 | snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x", | |
176 | netlist->major, netlist->minor, | |
0128cc6e JK |
177 | netlist->type >> 16, netlist->type & 0xFFFF, |
178 | netlist->rev, netlist->cust_ver); | |
e120a9ab JK |
179 | } |
180 | ||
0128cc6e JK |
181 | static void |
182 | ice_info_pending_netlist_build(struct ice_pf __always_unused *pf, | |
183 | struct ice_info_ctx *ctx) | |
e120a9ab JK |
184 | { |
185 | struct ice_netlist_info *netlist = &ctx->pending_netlist; | |
186 | ||
187 | if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) | |
188 | snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash); | |
e120a9ab JK |
189 | } |
190 | ||
2c4fe41d JK |
191 | #define fixed(key, getter) { ICE_VERSION_FIXED, key, getter, NULL } |
192 | #define running(key, getter) { ICE_VERSION_RUNNING, key, getter, NULL } | |
193 | #define stored(key, getter, fallback) { ICE_VERSION_STORED, key, getter, fallback } | |
194 | ||
195 | /* The combined() macro inserts both the running entry as well as a stored | |
196 | * entry. The running entry will always report the version from the active | |
197 | * handler. The stored entry will first try the pending handler, and fallback | |
198 | * to the active handler if the pending function does not report a version. | |
199 | * The pending handler should check the status of a pending update for the | |
200 | * relevant flash component. It should only fill in the buffer in the case | |
201 | * where a valid pending version is available. This ensures that the related | |
202 | * stored and running versions remain in sync, and that stored versions are | |
203 | * correctly reported as expected. | |
204 | */ | |
205 | #define combined(key, active, pending) \ | |
206 | running(key, active), \ | |
207 | stored(key, pending, active) | |
ff2e5c70 JK |
208 | |
209 | enum ice_version_type { | |
210 | ICE_VERSION_FIXED, | |
211 | ICE_VERSION_RUNNING, | |
212 | ICE_VERSION_STORED, | |
213 | }; | |
214 | ||
215 | static const struct ice_devlink_version { | |
216 | enum ice_version_type type; | |
217 | const char *key; | |
0128cc6e JK |
218 | void (*getter)(struct ice_pf *pf, struct ice_info_ctx *ctx); |
219 | void (*fallback)(struct ice_pf *pf, struct ice_info_ctx *ctx); | |
ff2e5c70 | 220 | } ice_devlink_versions[] = { |
e961b679 | 221 | fixed(DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, ice_info_pba), |
ff2e5c70 JK |
222 | running(DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, ice_info_fw_mgmt), |
223 | running("fw.mgmt.api", ice_info_fw_api), | |
224 | running("fw.mgmt.build", ice_info_fw_build), | |
e67fbcfb | 225 | combined(DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, ice_info_orom_ver, ice_info_pending_orom_ver), |
2c4fe41d JK |
226 | combined("fw.psid.api", ice_info_nvm_ver, ice_info_pending_nvm_ver), |
227 | combined(DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, ice_info_eetrack, ice_info_pending_eetrack), | |
ff2e5c70 JK |
228 | running("fw.app.name", ice_info_ddp_pkg_name), |
229 | running(DEVLINK_INFO_VERSION_GENERIC_FW_APP, ice_info_ddp_pkg_version), | |
410d0687 | 230 | running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id), |
e120a9ab JK |
231 | combined("fw.netlist", ice_info_netlist_ver, ice_info_pending_netlist_ver), |
232 | combined("fw.netlist.build", ice_info_netlist_build, ice_info_pending_netlist_build), | |
ff2e5c70 JK |
233 | }; |
234 | ||
235 | /** | |
236 | * ice_devlink_info_get - .info_get devlink handler | |
237 | * @devlink: devlink instance structure | |
238 | * @req: the devlink info request | |
239 | * @extack: extended netdev ack structure | |
240 | * | |
241 | * Callback for the devlink .info_get operation. Reports information about the | |
242 | * device. | |
243 | * | |
e961b679 | 244 | * Return: zero on success or an error code on failure. |
ff2e5c70 JK |
245 | */ |
246 | static int ice_devlink_info_get(struct devlink *devlink, | |
247 | struct devlink_info_req *req, | |
248 | struct netlink_ext_ack *extack) | |
249 | { | |
250 | struct ice_pf *pf = devlink_priv(devlink); | |
2c4fe41d JK |
251 | struct device *dev = ice_pf_to_dev(pf); |
252 | struct ice_hw *hw = &pf->hw; | |
74789085 | 253 | struct ice_info_ctx *ctx; |
ff2e5c70 JK |
254 | size_t i; |
255 | int err; | |
256 | ||
1c08052e JK |
257 | err = ice_wait_for_reset(pf, 10 * HZ); |
258 | if (err) { | |
259 | NL_SET_ERR_MSG_MOD(extack, "Device is busy resetting"); | |
260 | return err; | |
261 | } | |
262 | ||
74789085 JK |
263 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
264 | if (!ctx) | |
265 | return -ENOMEM; | |
266 | ||
2c4fe41d | 267 | /* discover capabilities first */ |
2ccc1c1c TN |
268 | err = ice_discover_dev_caps(hw, &ctx->dev_caps); |
269 | if (err) { | |
5f87ec48 | 270 | dev_dbg(dev, "Failed to discover device capabilities, status %d aq_err %s\n", |
2ccc1c1c | 271 | err, ice_aq_str(hw->adminq.sq_last_status)); |
d5f84ae9 | 272 | NL_SET_ERR_MSG_MOD(extack, "Unable to discover device capabilities"); |
2c4fe41d JK |
273 | goto out_free_ctx; |
274 | } | |
275 | ||
e67fbcfb | 276 | if (ctx->dev_caps.common_cap.nvm_update_pending_orom) { |
2ccc1c1c TN |
277 | err = ice_get_inactive_orom_ver(hw, &ctx->pending_orom); |
278 | if (err) { | |
5f87ec48 | 279 | dev_dbg(dev, "Unable to read inactive Option ROM version data, status %d aq_err %s\n", |
2ccc1c1c | 280 | err, ice_aq_str(hw->adminq.sq_last_status)); |
e67fbcfb JK |
281 | |
282 | /* disable display of pending Option ROM */ | |
283 | ctx->dev_caps.common_cap.nvm_update_pending_orom = false; | |
284 | } | |
285 | } | |
286 | ||
2c4fe41d | 287 | if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) { |
2ccc1c1c TN |
288 | err = ice_get_inactive_nvm_ver(hw, &ctx->pending_nvm); |
289 | if (err) { | |
5f87ec48 | 290 | dev_dbg(dev, "Unable to read inactive NVM version data, status %d aq_err %s\n", |
2ccc1c1c | 291 | err, ice_aq_str(hw->adminq.sq_last_status)); |
2c4fe41d JK |
292 | |
293 | /* disable display of pending Option ROM */ | |
294 | ctx->dev_caps.common_cap.nvm_update_pending_nvm = false; | |
295 | } | |
296 | } | |
297 | ||
e120a9ab | 298 | if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) { |
2ccc1c1c TN |
299 | err = ice_get_inactive_netlist_ver(hw, &ctx->pending_netlist); |
300 | if (err) { | |
5f87ec48 | 301 | dev_dbg(dev, "Unable to read inactive Netlist version data, status %d aq_err %s\n", |
2ccc1c1c | 302 | err, ice_aq_str(hw->adminq.sq_last_status)); |
e120a9ab JK |
303 | |
304 | /* disable display of pending Option ROM */ | |
305 | ctx->dev_caps.common_cap.nvm_update_pending_netlist = false; | |
306 | } | |
307 | } | |
308 | ||
ff2e5c70 JK |
309 | err = devlink_info_driver_name_put(req, KBUILD_MODNAME); |
310 | if (err) { | |
311 | NL_SET_ERR_MSG_MOD(extack, "Unable to set driver name"); | |
74789085 | 312 | goto out_free_ctx; |
ff2e5c70 JK |
313 | } |
314 | ||
74789085 | 315 | ice_info_get_dsn(pf, ctx); |
ff2e5c70 | 316 | |
74789085 | 317 | err = devlink_info_serial_number_put(req, ctx->buf); |
ff2e5c70 JK |
318 | if (err) { |
319 | NL_SET_ERR_MSG_MOD(extack, "Unable to set serial number"); | |
74789085 | 320 | goto out_free_ctx; |
ff2e5c70 JK |
321 | } |
322 | ||
323 | for (i = 0; i < ARRAY_SIZE(ice_devlink_versions); i++) { | |
324 | enum ice_version_type type = ice_devlink_versions[i].type; | |
325 | const char *key = ice_devlink_versions[i].key; | |
326 | ||
74789085 JK |
327 | memset(ctx->buf, 0, sizeof(ctx->buf)); |
328 | ||
0128cc6e | 329 | ice_devlink_versions[i].getter(pf, ctx); |
ff2e5c70 | 330 | |
2c4fe41d JK |
331 | /* If the default getter doesn't report a version, use the |
332 | * fallback function. This is primarily useful in the case of | |
333 | * "stored" versions that want to report the same value as the | |
334 | * running version in the normal case of no pending update. | |
335 | */ | |
0128cc6e JK |
336 | if (ctx->buf[0] == '\0' && ice_devlink_versions[i].fallback) |
337 | ice_devlink_versions[i].fallback(pf, ctx); | |
2c4fe41d | 338 | |
74789085 JK |
339 | /* Do not report missing versions */ |
340 | if (ctx->buf[0] == '\0') | |
341 | continue; | |
342 | ||
ff2e5c70 JK |
343 | switch (type) { |
344 | case ICE_VERSION_FIXED: | |
74789085 | 345 | err = devlink_info_version_fixed_put(req, key, ctx->buf); |
ff2e5c70 JK |
346 | if (err) { |
347 | NL_SET_ERR_MSG_MOD(extack, "Unable to set fixed version"); | |
74789085 | 348 | goto out_free_ctx; |
ff2e5c70 JK |
349 | } |
350 | break; | |
351 | case ICE_VERSION_RUNNING: | |
74789085 | 352 | err = devlink_info_version_running_put(req, key, ctx->buf); |
ff2e5c70 JK |
353 | if (err) { |
354 | NL_SET_ERR_MSG_MOD(extack, "Unable to set running version"); | |
74789085 | 355 | goto out_free_ctx; |
ff2e5c70 JK |
356 | } |
357 | break; | |
358 | case ICE_VERSION_STORED: | |
74789085 | 359 | err = devlink_info_version_stored_put(req, key, ctx->buf); |
ff2e5c70 JK |
360 | if (err) { |
361 | NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version"); | |
74789085 | 362 | goto out_free_ctx; |
ff2e5c70 JK |
363 | } |
364 | break; | |
365 | } | |
366 | } | |
367 | ||
74789085 JK |
368 | out_free_ctx: |
369 | kfree(ctx); | |
370 | return err; | |
ff2e5c70 JK |
371 | } |
372 | ||
399e27db JK |
373 | /** |
374 | * ice_devlink_reload_empr_start - Start EMP reset to activate new firmware | |
375 | * @devlink: pointer to the devlink instance to reload | |
376 | * @netns_change: if true, the network namespace is changing | |
377 | * @action: the action to perform. Must be DEVLINK_RELOAD_ACTION_FW_ACTIVATE | |
378 | * @limit: limits on what reload should do, such as not resetting | |
379 | * @extack: netlink extended ACK structure | |
380 | * | |
381 | * Allow user to activate new Embedded Management Processor firmware by | |
382 | * issuing device specific EMP reset. Called in response to | |
383 | * a DEVLINK_CMD_RELOAD with the DEVLINK_RELOAD_ACTION_FW_ACTIVATE. | |
384 | * | |
385 | * Note that teardown and rebuild of the driver state happens automatically as | |
386 | * part of an interrupt and watchdog task. This is because all physical | |
387 | * functions on the device must be able to reset when an EMP reset occurs from | |
388 | * any source. | |
389 | */ | |
390 | static int | |
391 | ice_devlink_reload_empr_start(struct devlink *devlink, bool netns_change, | |
392 | enum devlink_reload_action action, | |
393 | enum devlink_reload_limit limit, | |
394 | struct netlink_ext_ack *extack) | |
395 | { | |
396 | struct ice_pf *pf = devlink_priv(devlink); | |
397 | struct device *dev = ice_pf_to_dev(pf); | |
398 | struct ice_hw *hw = &pf->hw; | |
399 | u8 pending; | |
400 | int err; | |
401 | ||
402 | err = ice_get_pending_updates(pf, &pending, extack); | |
403 | if (err) | |
404 | return err; | |
405 | ||
406 | /* pending is a bitmask of which flash banks have a pending update, | |
407 | * including the main NVM bank, the Option ROM bank, and the netlist | |
408 | * bank. If any of these bits are set, then there is a pending update | |
409 | * waiting to be activated. | |
410 | */ | |
411 | if (!pending) { | |
412 | NL_SET_ERR_MSG_MOD(extack, "No pending firmware update"); | |
413 | return -ECANCELED; | |
414 | } | |
415 | ||
416 | if (pf->fw_emp_reset_disabled) { | |
417 | NL_SET_ERR_MSG_MOD(extack, "EMP reset is not available. To activate firmware, a reboot or power cycle is needed"); | |
418 | return -ECANCELED; | |
419 | } | |
420 | ||
421 | dev_dbg(dev, "Issuing device EMP reset to activate firmware\n"); | |
422 | ||
423 | err = ice_aq_nvm_update_empr(hw); | |
424 | if (err) { | |
425 | dev_err(dev, "Failed to trigger EMP device reset to reload firmware, err %d aq_err %s\n", | |
426 | err, ice_aq_str(hw->adminq.sq_last_status)); | |
427 | NL_SET_ERR_MSG_MOD(extack, "Failed to trigger EMP device reset to reload firmware"); | |
428 | return err; | |
429 | } | |
430 | ||
431 | return 0; | |
432 | } | |
433 | ||
434 | /** | |
435 | * ice_devlink_reload_empr_finish - Wait for EMP reset to finish | |
436 | * @devlink: pointer to the devlink instance reloading | |
437 | * @action: the action requested | |
438 | * @limit: limits imposed by userspace, such as not resetting | |
439 | * @actions_performed: on return, indicate what actions actually performed | |
440 | * @extack: netlink extended ACK structure | |
441 | * | |
442 | * Wait for driver to finish rebuilding after EMP reset is completed. This | |
443 | * includes time to wait for both the actual device reset as well as the time | |
444 | * for the driver's rebuild to complete. | |
445 | */ | |
446 | static int | |
447 | ice_devlink_reload_empr_finish(struct devlink *devlink, | |
448 | enum devlink_reload_action action, | |
449 | enum devlink_reload_limit limit, | |
450 | u32 *actions_performed, | |
451 | struct netlink_ext_ack *extack) | |
452 | { | |
453 | struct ice_pf *pf = devlink_priv(devlink); | |
454 | int err; | |
455 | ||
456 | *actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); | |
457 | ||
458 | err = ice_wait_for_reset(pf, 60 * HZ); | |
459 | if (err) { | |
460 | NL_SET_ERR_MSG_MOD(extack, "Device still resetting after 1 minute"); | |
461 | return err; | |
462 | } | |
463 | ||
464 | return 0; | |
465 | } | |
466 | ||
1adf7ead | 467 | static const struct devlink_ops ice_devlink_ops = { |
50db1bca | 468 | .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, |
399e27db JK |
469 | .reload_actions = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), |
470 | /* The ice driver currently does not support driver reinit */ | |
471 | .reload_down = ice_devlink_reload_empr_start, | |
472 | .reload_up = ice_devlink_reload_empr_finish, | |
3ea9bd5d MS |
473 | .eswitch_mode_get = ice_eswitch_mode_get, |
474 | .eswitch_mode_set = ice_eswitch_mode_set, | |
ff2e5c70 | 475 | .info_get = ice_devlink_info_get, |
d69ea414 | 476 | .flash_update = ice_devlink_flash_update, |
1adf7ead JK |
477 | }; |
478 | ||
e523af4e SS |
479 | static int |
480 | ice_devlink_enable_roce_get(struct devlink *devlink, u32 id, | |
481 | struct devlink_param_gset_ctx *ctx) | |
482 | { | |
483 | struct ice_pf *pf = devlink_priv(devlink); | |
484 | ||
7b62483f | 485 | ctx->val.vbool = pf->rdma_mode & IIDC_RDMA_PROTOCOL_ROCEV2 ? true : false; |
e523af4e SS |
486 | |
487 | return 0; | |
488 | } | |
489 | ||
490 | static int | |
491 | ice_devlink_enable_roce_set(struct devlink *devlink, u32 id, | |
492 | struct devlink_param_gset_ctx *ctx) | |
493 | { | |
494 | struct ice_pf *pf = devlink_priv(devlink); | |
495 | bool roce_ena = ctx->val.vbool; | |
496 | int ret; | |
497 | ||
498 | if (!roce_ena) { | |
499 | ice_unplug_aux_dev(pf); | |
500 | pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_ROCEV2; | |
501 | return 0; | |
502 | } | |
503 | ||
504 | pf->rdma_mode |= IIDC_RDMA_PROTOCOL_ROCEV2; | |
505 | ret = ice_plug_aux_dev(pf); | |
506 | if (ret) | |
507 | pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_ROCEV2; | |
508 | ||
509 | return ret; | |
510 | } | |
511 | ||
512 | static int | |
513 | ice_devlink_enable_roce_validate(struct devlink *devlink, u32 id, | |
514 | union devlink_param_value val, | |
515 | struct netlink_ext_ack *extack) | |
516 | { | |
517 | struct ice_pf *pf = devlink_priv(devlink); | |
518 | ||
519 | if (!test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) | |
520 | return -EOPNOTSUPP; | |
521 | ||
522 | if (pf->rdma_mode & IIDC_RDMA_PROTOCOL_IWARP) { | |
523 | NL_SET_ERR_MSG_MOD(extack, "iWARP is currently enabled. This device cannot enable iWARP and RoCEv2 simultaneously"); | |
524 | return -EOPNOTSUPP; | |
525 | } | |
526 | ||
527 | return 0; | |
528 | } | |
529 | ||
530 | static int | |
531 | ice_devlink_enable_iw_get(struct devlink *devlink, u32 id, | |
532 | struct devlink_param_gset_ctx *ctx) | |
533 | { | |
534 | struct ice_pf *pf = devlink_priv(devlink); | |
535 | ||
536 | ctx->val.vbool = pf->rdma_mode & IIDC_RDMA_PROTOCOL_IWARP; | |
537 | ||
538 | return 0; | |
539 | } | |
540 | ||
541 | static int | |
542 | ice_devlink_enable_iw_set(struct devlink *devlink, u32 id, | |
543 | struct devlink_param_gset_ctx *ctx) | |
544 | { | |
545 | struct ice_pf *pf = devlink_priv(devlink); | |
546 | bool iw_ena = ctx->val.vbool; | |
547 | int ret; | |
548 | ||
549 | if (!iw_ena) { | |
550 | ice_unplug_aux_dev(pf); | |
551 | pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_IWARP; | |
552 | return 0; | |
553 | } | |
554 | ||
555 | pf->rdma_mode |= IIDC_RDMA_PROTOCOL_IWARP; | |
556 | ret = ice_plug_aux_dev(pf); | |
557 | if (ret) | |
558 | pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_IWARP; | |
559 | ||
560 | return ret; | |
561 | } | |
562 | ||
563 | static int | |
564 | ice_devlink_enable_iw_validate(struct devlink *devlink, u32 id, | |
565 | union devlink_param_value val, | |
566 | struct netlink_ext_ack *extack) | |
567 | { | |
568 | struct ice_pf *pf = devlink_priv(devlink); | |
569 | ||
570 | if (!test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) | |
571 | return -EOPNOTSUPP; | |
572 | ||
573 | if (pf->rdma_mode & IIDC_RDMA_PROTOCOL_ROCEV2) { | |
574 | NL_SET_ERR_MSG_MOD(extack, "RoCEv2 is currently enabled. This device cannot enable iWARP and RoCEv2 simultaneously"); | |
575 | return -EOPNOTSUPP; | |
576 | } | |
577 | ||
578 | return 0; | |
579 | } | |
580 | ||
581 | static const struct devlink_param ice_devlink_params[] = { | |
582 | DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_RUNTIME), | |
583 | ice_devlink_enable_roce_get, | |
584 | ice_devlink_enable_roce_set, | |
585 | ice_devlink_enable_roce_validate), | |
586 | DEVLINK_PARAM_GENERIC(ENABLE_IWARP, BIT(DEVLINK_PARAM_CMODE_RUNTIME), | |
587 | ice_devlink_enable_iw_get, | |
588 | ice_devlink_enable_iw_set, | |
589 | ice_devlink_enable_iw_validate), | |
590 | ||
591 | }; | |
592 | ||
1adf7ead JK |
593 | static void ice_devlink_free(void *devlink_ptr) |
594 | { | |
595 | devlink_free((struct devlink *)devlink_ptr); | |
596 | } | |
597 | ||
598 | /** | |
599 | * ice_allocate_pf - Allocate devlink and return PF structure pointer | |
600 | * @dev: the device to allocate for | |
601 | * | |
602 | * Allocate a devlink instance for this device and return the private area as | |
603 | * the PF structure. The devlink memory is kept track of through devres by | |
604 | * adding an action to remove it when unwinding. | |
605 | */ | |
606 | struct ice_pf *ice_allocate_pf(struct device *dev) | |
607 | { | |
608 | struct devlink *devlink; | |
609 | ||
919d13a7 | 610 | devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf), dev); |
1adf7ead JK |
611 | if (!devlink) |
612 | return NULL; | |
613 | ||
614 | /* Add an action to teardown the devlink when unwinding the driver */ | |
7c1b694a | 615 | if (devm_add_action_or_reset(dev, ice_devlink_free, devlink)) |
1adf7ead | 616 | return NULL; |
1adf7ead JK |
617 | |
618 | return devlink_priv(devlink); | |
619 | } | |
620 | ||
621 | /** | |
622 | * ice_devlink_register - Register devlink interface for this PF | |
623 | * @pf: the PF to register the devlink for. | |
624 | * | |
625 | * Register the devlink instance associated with this physical function. | |
626 | * | |
627 | * Return: zero on success or an error code on failure. | |
628 | */ | |
db4278c5 | 629 | void ice_devlink_register(struct ice_pf *pf) |
1adf7ead JK |
630 | { |
631 | struct devlink *devlink = priv_to_devlink(pf); | |
1adf7ead | 632 | |
399e27db | 633 | devlink_set_features(devlink, DEVLINK_F_RELOAD); |
db4278c5 | 634 | devlink_register(devlink); |
1adf7ead JK |
635 | } |
636 | ||
637 | /** | |
638 | * ice_devlink_unregister - Unregister devlink resources for this PF. | |
639 | * @pf: the PF structure to cleanup | |
640 | * | |
641 | * Releases resources used by devlink and cleans up associated memory. | |
642 | */ | |
643 | void ice_devlink_unregister(struct ice_pf *pf) | |
644 | { | |
645 | devlink_unregister(priv_to_devlink(pf)); | |
646 | } | |
647 | ||
e523af4e SS |
648 | int ice_devlink_register_params(struct ice_pf *pf) |
649 | { | |
650 | struct devlink *devlink = priv_to_devlink(pf); | |
651 | union devlink_param_value value; | |
652 | int err; | |
653 | ||
654 | err = devlink_params_register(devlink, ice_devlink_params, | |
655 | ARRAY_SIZE(ice_devlink_params)); | |
656 | if (err) | |
657 | return err; | |
658 | ||
659 | value.vbool = false; | |
660 | devlink_param_driverinit_value_set(devlink, | |
661 | DEVLINK_PARAM_GENERIC_ID_ENABLE_IWARP, | |
662 | value); | |
663 | ||
664 | value.vbool = test_bit(ICE_FLAG_RDMA_ENA, pf->flags) ? true : false; | |
665 | devlink_param_driverinit_value_set(devlink, | |
666 | DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, | |
667 | value); | |
668 | ||
669 | return 0; | |
670 | } | |
671 | ||
672 | void ice_devlink_unregister_params(struct ice_pf *pf) | |
673 | { | |
674 | devlink_params_unregister(priv_to_devlink(pf), ice_devlink_params, | |
675 | ARRAY_SIZE(ice_devlink_params)); | |
676 | } | |
677 | ||
1adf7ead | 678 | /** |
2ae0aa47 WD |
679 | * ice_devlink_create_pf_port - Create a devlink port for this PF |
680 | * @pf: the PF to create a devlink port for | |
1adf7ead | 681 | * |
2ae0aa47 | 682 | * Create and register a devlink_port for this PF. |
1adf7ead JK |
683 | * |
684 | * Return: zero on success or an error code on failure. | |
685 | */ | |
2ae0aa47 | 686 | int ice_devlink_create_pf_port(struct ice_pf *pf) |
1adf7ead | 687 | { |
71ad8d55 | 688 | struct devlink_port_attrs attrs = {}; |
2ae0aa47 | 689 | struct devlink_port *devlink_port; |
48d40025 | 690 | struct devlink *devlink; |
2ae0aa47 | 691 | struct ice_vsi *vsi; |
48d40025 | 692 | struct device *dev; |
1adf7ead JK |
693 | int err; |
694 | ||
48d40025 | 695 | dev = ice_pf_to_dev(pf); |
2ae0aa47 WD |
696 | |
697 | devlink_port = &pf->devlink_port; | |
698 | ||
699 | vsi = ice_get_main_vsi(pf); | |
700 | if (!vsi) | |
701 | return -EIO; | |
1adf7ead | 702 | |
71ad8d55 | 703 | attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; |
2ae0aa47 WD |
704 | attrs.phys.port_number = pf->hw.bus.func; |
705 | devlink_port_attrs_set(devlink_port, &attrs); | |
706 | devlink = priv_to_devlink(pf); | |
707 | ||
708 | err = devlink_port_register(devlink, devlink_port, vsi->idx); | |
1adf7ead | 709 | if (err) { |
2ae0aa47 WD |
710 | dev_err(dev, "Failed to create devlink port for PF %d, error %d\n", |
711 | pf->hw.pf_id, err); | |
1adf7ead JK |
712 | return err; |
713 | } | |
714 | ||
2ae0aa47 WD |
715 | return 0; |
716 | } | |
717 | ||
718 | /** | |
719 | * ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF | |
720 | * @pf: the PF to cleanup | |
721 | * | |
722 | * Unregisters the devlink_port structure associated with this PF. | |
723 | */ | |
724 | void ice_devlink_destroy_pf_port(struct ice_pf *pf) | |
725 | { | |
726 | struct devlink_port *devlink_port; | |
727 | ||
728 | devlink_port = &pf->devlink_port; | |
729 | ||
730 | devlink_port_type_clear(devlink_port); | |
731 | devlink_port_unregister(devlink_port); | |
732 | } | |
733 | ||
734 | /** | |
735 | * ice_devlink_create_vf_port - Create a devlink port for this VF | |
736 | * @vf: the VF to create a port for | |
737 | * | |
738 | * Create and register a devlink_port for this VF. | |
739 | * | |
740 | * Return: zero on success or an error code on failure. | |
741 | */ | |
742 | int ice_devlink_create_vf_port(struct ice_vf *vf) | |
743 | { | |
744 | struct devlink_port_attrs attrs = {}; | |
745 | struct devlink_port *devlink_port; | |
746 | struct devlink *devlink; | |
747 | struct ice_vsi *vsi; | |
748 | struct device *dev; | |
749 | struct ice_pf *pf; | |
750 | int err; | |
751 | ||
752 | pf = vf->pf; | |
753 | dev = ice_pf_to_dev(pf); | |
754 | vsi = ice_get_vf_vsi(vf); | |
755 | devlink_port = &vf->devlink_port; | |
756 | ||
757 | attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; | |
758 | attrs.pci_vf.pf = pf->hw.bus.func; | |
759 | attrs.pci_vf.vf = vf->vf_id; | |
760 | ||
761 | devlink_port_attrs_set(devlink_port, &attrs); | |
762 | devlink = priv_to_devlink(pf); | |
763 | ||
764 | err = devlink_port_register(devlink, devlink_port, vsi->idx); | |
765 | if (err) { | |
766 | dev_err(dev, "Failed to create devlink port for VF %d, error %d\n", | |
767 | vf->vf_id, err); | |
768 | return err; | |
769 | } | |
48d40025 | 770 | |
1adf7ead JK |
771 | return 0; |
772 | } | |
773 | ||
774 | /** | |
2ae0aa47 WD |
775 | * ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF |
776 | * @vf: the VF to cleanup | |
1adf7ead | 777 | * |
2ae0aa47 | 778 | * Unregisters the devlink_port structure associated with this VF. |
1adf7ead | 779 | */ |
2ae0aa47 | 780 | void ice_devlink_destroy_vf_port(struct ice_vf *vf) |
1adf7ead | 781 | { |
2ae0aa47 | 782 | struct devlink_port *devlink_port; |
48d40025 | 783 | |
2ae0aa47 | 784 | devlink_port = &vf->devlink_port; |
48d40025 | 785 | |
2ae0aa47 WD |
786 | devlink_port_type_clear(devlink_port); |
787 | devlink_port_unregister(devlink_port); | |
1adf7ead | 788 | } |
dce730f1 JK |
789 | |
790 | /** | |
78ad87da | 791 | * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents |
dce730f1 | 792 | * @devlink: the devlink instance |
d4602a9f | 793 | * @ops: the devlink region being snapshotted |
dce730f1 JK |
794 | * @extack: extended ACK response structure |
795 | * @data: on exit points to snapshot data buffer | |
796 | * | |
797 | * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for | |
78ad87da JK |
798 | * the nvm-flash devlink region. It captures a snapshot of the full NVM flash |
799 | * contents, including both banks of flash. This snapshot can later be viewed | |
800 | * via the devlink-region interface. | |
801 | * | |
802 | * It captures the flash using the FLASH_ONLY bit set when reading via | |
803 | * firmware, so it does not read the current Shadow RAM contents. For that, | |
804 | * use the shadow-ram region. | |
dce730f1 JK |
805 | * |
806 | * @returns zero on success, and updates the data pointer. Returns a non-zero | |
807 | * error code on failure. | |
808 | */ | |
809 | static int ice_devlink_nvm_snapshot(struct devlink *devlink, | |
d4602a9f | 810 | const struct devlink_region_ops *ops, |
dce730f1 JK |
811 | struct netlink_ext_ack *extack, u8 **data) |
812 | { | |
813 | struct ice_pf *pf = devlink_priv(devlink); | |
814 | struct device *dev = ice_pf_to_dev(pf); | |
815 | struct ice_hw *hw = &pf->hw; | |
dce730f1 JK |
816 | void *nvm_data; |
817 | u32 nvm_size; | |
5518ac2a | 818 | int status; |
dce730f1 | 819 | |
9af368fa | 820 | nvm_size = hw->flash.flash_size; |
dce730f1 JK |
821 | nvm_data = vzalloc(nvm_size); |
822 | if (!nvm_data) | |
823 | return -ENOMEM; | |
824 | ||
825 | status = ice_acquire_nvm(hw, ICE_RES_READ); | |
826 | if (status) { | |
827 | dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", | |
828 | status, hw->adminq.sq_last_status); | |
829 | NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); | |
830 | vfree(nvm_data); | |
c1484691 | 831 | return status; |
dce730f1 JK |
832 | } |
833 | ||
834 | status = ice_read_flat_nvm(hw, 0, &nvm_size, nvm_data, false); | |
835 | if (status) { | |
836 | dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n", | |
837 | nvm_size, status, hw->adminq.sq_last_status); | |
838 | NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents"); | |
839 | ice_release_nvm(hw); | |
840 | vfree(nvm_data); | |
c1484691 | 841 | return status; |
dce730f1 JK |
842 | } |
843 | ||
844 | ice_release_nvm(hw); | |
845 | ||
846 | *data = nvm_data; | |
847 | ||
848 | return 0; | |
849 | } | |
850 | ||
78ad87da JK |
851 | /** |
852 | * ice_devlink_sram_snapshot - Capture a snapshot of the Shadow RAM contents | |
853 | * @devlink: the devlink instance | |
854 | * @ops: the devlink region being snapshotted | |
855 | * @extack: extended ACK response structure | |
856 | * @data: on exit points to snapshot data buffer | |
857 | * | |
858 | * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for | |
859 | * the shadow-ram devlink region. It captures a snapshot of the shadow ram | |
860 | * contents. This snapshot can later be viewed via the devlink-region | |
861 | * interface. | |
862 | * | |
863 | * @returns zero on success, and updates the data pointer. Returns a non-zero | |
864 | * error code on failure. | |
865 | */ | |
866 | static int | |
867 | ice_devlink_sram_snapshot(struct devlink *devlink, | |
868 | const struct devlink_region_ops __always_unused *ops, | |
869 | struct netlink_ext_ack *extack, u8 **data) | |
870 | { | |
871 | struct ice_pf *pf = devlink_priv(devlink); | |
872 | struct device *dev = ice_pf_to_dev(pf); | |
873 | struct ice_hw *hw = &pf->hw; | |
874 | u8 *sram_data; | |
875 | u32 sram_size; | |
876 | int err; | |
877 | ||
878 | sram_size = hw->flash.sr_words * 2u; | |
879 | sram_data = vzalloc(sram_size); | |
880 | if (!sram_data) | |
881 | return -ENOMEM; | |
882 | ||
883 | err = ice_acquire_nvm(hw, ICE_RES_READ); | |
884 | if (err) { | |
885 | dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", | |
886 | err, hw->adminq.sq_last_status); | |
887 | NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); | |
888 | vfree(sram_data); | |
889 | return err; | |
890 | } | |
891 | ||
892 | /* Read from the Shadow RAM, rather than directly from NVM */ | |
893 | err = ice_read_flat_nvm(hw, 0, &sram_size, sram_data, true); | |
894 | if (err) { | |
895 | dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n", | |
896 | sram_size, err, hw->adminq.sq_last_status); | |
897 | NL_SET_ERR_MSG_MOD(extack, | |
898 | "Failed to read Shadow RAM contents"); | |
899 | ice_release_nvm(hw); | |
900 | vfree(sram_data); | |
901 | return err; | |
902 | } | |
903 | ||
904 | ice_release_nvm(hw); | |
905 | ||
906 | *data = sram_data; | |
907 | ||
908 | return 0; | |
909 | } | |
910 | ||
8d7aab35 JK |
911 | /** |
912 | * ice_devlink_devcaps_snapshot - Capture snapshot of device capabilities | |
913 | * @devlink: the devlink instance | |
d4602a9f | 914 | * @ops: the devlink region being snapshotted |
8d7aab35 JK |
915 | * @extack: extended ACK response structure |
916 | * @data: on exit points to snapshot data buffer | |
917 | * | |
918 | * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for | |
919 | * the device-caps devlink region. It captures a snapshot of the device | |
920 | * capabilities reported by firmware. | |
921 | * | |
922 | * @returns zero on success, and updates the data pointer. Returns a non-zero | |
923 | * error code on failure. | |
924 | */ | |
925 | static int | |
926 | ice_devlink_devcaps_snapshot(struct devlink *devlink, | |
d4602a9f | 927 | const struct devlink_region_ops *ops, |
8d7aab35 JK |
928 | struct netlink_ext_ack *extack, u8 **data) |
929 | { | |
930 | struct ice_pf *pf = devlink_priv(devlink); | |
931 | struct device *dev = ice_pf_to_dev(pf); | |
932 | struct ice_hw *hw = &pf->hw; | |
8d7aab35 | 933 | void *devcaps; |
5518ac2a | 934 | int status; |
8d7aab35 JK |
935 | |
936 | devcaps = vzalloc(ICE_AQ_MAX_BUF_LEN); | |
937 | if (!devcaps) | |
938 | return -ENOMEM; | |
939 | ||
940 | status = ice_aq_list_caps(hw, devcaps, ICE_AQ_MAX_BUF_LEN, NULL, | |
941 | ice_aqc_opc_list_dev_caps, NULL); | |
942 | if (status) { | |
943 | dev_dbg(dev, "ice_aq_list_caps: failed to read device capabilities, err %d aq_err %d\n", | |
944 | status, hw->adminq.sq_last_status); | |
945 | NL_SET_ERR_MSG_MOD(extack, "Failed to read device capabilities"); | |
946 | vfree(devcaps); | |
c1484691 | 947 | return status; |
8d7aab35 JK |
948 | } |
949 | ||
950 | *data = (u8 *)devcaps; | |
951 | ||
952 | return 0; | |
953 | } | |
954 | ||
dce730f1 JK |
955 | static const struct devlink_region_ops ice_nvm_region_ops = { |
956 | .name = "nvm-flash", | |
957 | .destructor = vfree, | |
958 | .snapshot = ice_devlink_nvm_snapshot, | |
959 | }; | |
960 | ||
78ad87da JK |
961 | static const struct devlink_region_ops ice_sram_region_ops = { |
962 | .name = "shadow-ram", | |
963 | .destructor = vfree, | |
964 | .snapshot = ice_devlink_sram_snapshot, | |
965 | }; | |
966 | ||
8d7aab35 JK |
967 | static const struct devlink_region_ops ice_devcaps_region_ops = { |
968 | .name = "device-caps", | |
969 | .destructor = vfree, | |
970 | .snapshot = ice_devlink_devcaps_snapshot, | |
971 | }; | |
972 | ||
dce730f1 JK |
973 | /** |
974 | * ice_devlink_init_regions - Initialize devlink regions | |
975 | * @pf: the PF device structure | |
976 | * | |
977 | * Create devlink regions used to enable access to dump the contents of the | |
978 | * flash memory on the device. | |
979 | */ | |
980 | void ice_devlink_init_regions(struct ice_pf *pf) | |
981 | { | |
982 | struct devlink *devlink = priv_to_devlink(pf); | |
983 | struct device *dev = ice_pf_to_dev(pf); | |
78ad87da | 984 | u64 nvm_size, sram_size; |
dce730f1 | 985 | |
9af368fa | 986 | nvm_size = pf->hw.flash.flash_size; |
dce730f1 JK |
987 | pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1, |
988 | nvm_size); | |
989 | if (IS_ERR(pf->nvm_region)) { | |
990 | dev_err(dev, "failed to create NVM devlink region, err %ld\n", | |
991 | PTR_ERR(pf->nvm_region)); | |
992 | pf->nvm_region = NULL; | |
993 | } | |
8d7aab35 | 994 | |
78ad87da JK |
995 | sram_size = pf->hw.flash.sr_words * 2u; |
996 | pf->sram_region = devlink_region_create(devlink, &ice_sram_region_ops, | |
997 | 1, sram_size); | |
998 | if (IS_ERR(pf->sram_region)) { | |
999 | dev_err(dev, "failed to create shadow-ram devlink region, err %ld\n", | |
1000 | PTR_ERR(pf->sram_region)); | |
1001 | pf->sram_region = NULL; | |
1002 | } | |
1003 | ||
8d7aab35 JK |
1004 | pf->devcaps_region = devlink_region_create(devlink, |
1005 | &ice_devcaps_region_ops, 10, | |
1006 | ICE_AQ_MAX_BUF_LEN); | |
1007 | if (IS_ERR(pf->devcaps_region)) { | |
1008 | dev_err(dev, "failed to create device-caps devlink region, err %ld\n", | |
1009 | PTR_ERR(pf->devcaps_region)); | |
1010 | pf->devcaps_region = NULL; | |
1011 | } | |
dce730f1 JK |
1012 | } |
1013 | ||
1014 | /** | |
1015 | * ice_devlink_destroy_regions - Destroy devlink regions | |
1016 | * @pf: the PF device structure | |
1017 | * | |
1018 | * Remove previously created regions for this PF. | |
1019 | */ | |
1020 | void ice_devlink_destroy_regions(struct ice_pf *pf) | |
1021 | { | |
1022 | if (pf->nvm_region) | |
1023 | devlink_region_destroy(pf->nvm_region); | |
78ad87da JK |
1024 | |
1025 | if (pf->sram_region) | |
1026 | devlink_region_destroy(pf->sram_region); | |
1027 | ||
8d7aab35 JK |
1028 | if (pf->devcaps_region) |
1029 | devlink_region_destroy(pf->devcaps_region); | |
dce730f1 | 1030 | } |