Commit | Line | Data |
---|---|---|
d69ea414 JK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (C) 2018-2019, Intel Corporation. */ | |
3 | ||
4 | #include <asm/unaligned.h> | |
5 | #include <linux/uuid.h> | |
6 | #include <linux/crc32.h> | |
7 | #include <linux/pldmfw.h> | |
8 | #include "ice.h" | |
9 | #include "ice_fw_update.h" | |
10 | ||
11 | struct ice_fwu_priv { | |
12 | struct pldmfw context; | |
13 | ||
14 | struct ice_pf *pf; | |
15 | struct netlink_ext_ack *extack; | |
16 | ||
17 | /* Track which NVM banks to activate at the end of the update */ | |
18 | u8 activate_flags; | |
399e27db JK |
19 | |
20 | /* Track the firmware response of the required reset to complete the | |
21 | * flash update. | |
22 | * | |
23 | * 0 - ICE_AQC_NVM_POR_FLAG - A full power on is required | |
24 | * 1 - ICE_AQC_NVM_PERST_FLAG - A cold PCIe reset is required | |
25 | * 2 - ICE_AQC_NVM_EMPR_FLAG - An EMP reset is required | |
26 | */ | |
27 | u8 reset_level; | |
28 | ||
29 | /* Track if EMP reset is available */ | |
30 | u8 emp_reset_available; | |
d69ea414 JK |
31 | }; |
32 | ||
33 | /** | |
34 | * ice_send_package_data - Send record package data to firmware | |
35 | * @context: PLDM fw update structure | |
36 | * @data: pointer to the package data | |
37 | * @length: length of the package data | |
38 | * | |
39 | * Send a copy of the package data associated with the PLDM record matching | |
40 | * this device to the firmware. | |
41 | * | |
42 | * Note that this function sends an AdminQ command that will fail unless the | |
43 | * NVM resource has been acquired. | |
44 | * | |
45 | * Returns: zero on success, or a negative error code on failure. | |
46 | */ | |
47 | static int | |
48 | ice_send_package_data(struct pldmfw *context, const u8 *data, u16 length) | |
49 | { | |
50 | struct ice_fwu_priv *priv = container_of(context, struct ice_fwu_priv, context); | |
51 | struct netlink_ext_ack *extack = priv->extack; | |
52 | struct device *dev = context->dev; | |
53 | struct ice_pf *pf = priv->pf; | |
54 | struct ice_hw *hw = &pf->hw; | |
d69ea414 | 55 | u8 *package_data; |
5518ac2a | 56 | int status; |
d69ea414 | 57 | |
1e8249cc JK |
58 | dev_dbg(dev, "Sending PLDM record package data to firmware\n"); |
59 | ||
d69ea414 JK |
60 | package_data = kmemdup(data, length, GFP_KERNEL); |
61 | if (!package_data) | |
62 | return -ENOMEM; | |
63 | ||
64 | status = ice_nvm_set_pkg_data(hw, false, package_data, length, NULL); | |
65 | ||
66 | kfree(package_data); | |
67 | ||
68 | if (status) { | |
5f87ec48 | 69 | dev_err(dev, "Failed to send record package data to firmware, err %d aq_err %s\n", |
5518ac2a | 70 | status, ice_aq_str(hw->adminq.sq_last_status)); |
d69ea414 JK |
71 | NL_SET_ERR_MSG_MOD(extack, "Failed to record package data to firmware"); |
72 | return -EIO; | |
73 | } | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
78 | /** | |
79 | * ice_check_component_response - Report firmware response to a component | |
80 | * @pf: device private data structure | |
81 | * @id: component id being checked | |
82 | * @response: indicates whether this component can be updated | |
83 | * @code: code indicating reason for response | |
84 | * @extack: netlink extended ACK structure | |
85 | * | |
86 | * Check whether firmware indicates if this component can be updated. Report | |
87 | * a suitable error message over the netlink extended ACK if the component | |
88 | * cannot be updated. | |
89 | * | |
90 | * Returns: zero if the component can be updated, or -ECANCELED of the | |
91 | * firmware indicates the component cannot be updated. | |
92 | */ | |
93 | static int | |
94 | ice_check_component_response(struct ice_pf *pf, u16 id, u8 response, u8 code, | |
95 | struct netlink_ext_ack *extack) | |
96 | { | |
97 | struct device *dev = ice_pf_to_dev(pf); | |
98 | const char *component; | |
99 | ||
100 | switch (id) { | |
101 | case NVM_COMP_ID_OROM: | |
102 | component = "fw.undi"; | |
103 | break; | |
104 | case NVM_COMP_ID_NVM: | |
105 | component = "fw.mgmt"; | |
106 | break; | |
107 | case NVM_COMP_ID_NETLIST: | |
108 | component = "fw.netlist"; | |
109 | break; | |
110 | default: | |
111 | WARN(1, "Unexpected unknown component identifier 0x%02x", id); | |
112 | return -EINVAL; | |
113 | } | |
114 | ||
115 | dev_dbg(dev, "%s: firmware response 0x%x, code 0x%x\n", | |
116 | component, response, code); | |
117 | ||
118 | switch (response) { | |
119 | case ICE_AQ_NVM_PASS_COMP_CAN_BE_UPDATED: | |
120 | /* firmware indicated this update is good to proceed */ | |
121 | return 0; | |
122 | case ICE_AQ_NVM_PASS_COMP_CAN_MAY_BE_UPDATEABLE: | |
123 | dev_warn(dev, "firmware recommends not updating %s, as it may result in a downgrade. continuing anyways\n", component); | |
124 | return 0; | |
125 | case ICE_AQ_NVM_PASS_COMP_CAN_NOT_BE_UPDATED: | |
126 | dev_info(dev, "firmware has rejected updating %s\n", component); | |
127 | break; | |
128 | } | |
129 | ||
130 | switch (code) { | |
131 | case ICE_AQ_NVM_PASS_COMP_STAMP_IDENTICAL_CODE: | |
132 | dev_err(dev, "Component comparison stamp for %s is identical to the running image\n", | |
133 | component); | |
134 | NL_SET_ERR_MSG_MOD(extack, "Component comparison stamp is identical to running image"); | |
135 | break; | |
136 | case ICE_AQ_NVM_PASS_COMP_STAMP_LOWER: | |
137 | dev_err(dev, "Component comparison stamp for %s is lower than the running image\n", | |
138 | component); | |
139 | NL_SET_ERR_MSG_MOD(extack, "Component comparison stamp is lower than running image"); | |
140 | break; | |
141 | case ICE_AQ_NVM_PASS_COMP_INVALID_STAMP_CODE: | |
142 | dev_err(dev, "Component comparison stamp for %s is invalid\n", | |
143 | component); | |
144 | NL_SET_ERR_MSG_MOD(extack, "Component comparison stamp is invalid"); | |
145 | break; | |
146 | case ICE_AQ_NVM_PASS_COMP_CONFLICT_CODE: | |
147 | dev_err(dev, "%s conflicts with a previous component table\n", | |
148 | component); | |
149 | NL_SET_ERR_MSG_MOD(extack, "Component table conflict occurred"); | |
150 | break; | |
151 | case ICE_AQ_NVM_PASS_COMP_PRE_REQ_NOT_MET_CODE: | |
152 | dev_err(dev, "Pre-requisites for component %s have not been met\n", | |
153 | component); | |
154 | NL_SET_ERR_MSG_MOD(extack, "Component pre-requisites not met"); | |
155 | break; | |
156 | case ICE_AQ_NVM_PASS_COMP_NOT_SUPPORTED_CODE: | |
157 | dev_err(dev, "%s is not a supported component\n", | |
158 | component); | |
159 | NL_SET_ERR_MSG_MOD(extack, "Component not supported"); | |
160 | break; | |
161 | case ICE_AQ_NVM_PASS_COMP_CANNOT_DOWNGRADE_CODE: | |
162 | dev_err(dev, "Security restrictions prevent %s from being downgraded\n", | |
163 | component); | |
164 | NL_SET_ERR_MSG_MOD(extack, "Component cannot be downgraded"); | |
165 | break; | |
166 | case ICE_AQ_NVM_PASS_COMP_INCOMPLETE_IMAGE_CODE: | |
167 | dev_err(dev, "Received an incomplete component image for %s\n", | |
168 | component); | |
169 | NL_SET_ERR_MSG_MOD(extack, "Incomplete component image"); | |
170 | break; | |
171 | case ICE_AQ_NVM_PASS_COMP_VER_STR_IDENTICAL_CODE: | |
172 | dev_err(dev, "Component version for %s is identical to the running image\n", | |
173 | component); | |
174 | NL_SET_ERR_MSG_MOD(extack, "Component version is identical to running image"); | |
175 | break; | |
176 | case ICE_AQ_NVM_PASS_COMP_VER_STR_LOWER_CODE: | |
177 | dev_err(dev, "Component version for %s is lower than the running image\n", | |
178 | component); | |
179 | NL_SET_ERR_MSG_MOD(extack, "Component version is lower than the running image"); | |
180 | break; | |
181 | default: | |
182 | dev_err(dev, "Unexpected response code 0x02%x for %s\n", | |
183 | code, component); | |
184 | NL_SET_ERR_MSG_MOD(extack, "Received unexpected response code from firmware"); | |
185 | break; | |
186 | } | |
187 | ||
188 | return -ECANCELED; | |
189 | } | |
190 | ||
191 | /** | |
192 | * ice_send_component_table - Send PLDM component table to firmware | |
193 | * @context: PLDM fw update structure | |
194 | * @component: the component to process | |
195 | * @transfer_flag: relative transfer order of this component | |
196 | * | |
197 | * Read relevant data from the component and forward it to the device | |
198 | * firmware. Check the response to determine if the firmware indicates that | |
199 | * the update can proceed. | |
200 | * | |
201 | * This function sends AdminQ commands related to the NVM, and assumes that | |
202 | * the NVM resource has been acquired. | |
203 | * | |
204 | * Returns: zero on success, or a negative error code on failure. | |
205 | */ | |
206 | static int | |
207 | ice_send_component_table(struct pldmfw *context, struct pldmfw_component *component, | |
208 | u8 transfer_flag) | |
209 | { | |
210 | struct ice_fwu_priv *priv = container_of(context, struct ice_fwu_priv, context); | |
211 | struct netlink_ext_ack *extack = priv->extack; | |
212 | struct ice_aqc_nvm_comp_tbl *comp_tbl; | |
213 | u8 comp_response, comp_response_code; | |
214 | struct device *dev = context->dev; | |
215 | struct ice_pf *pf = priv->pf; | |
216 | struct ice_hw *hw = &pf->hw; | |
d69ea414 | 217 | size_t length; |
5518ac2a | 218 | int status; |
d69ea414 JK |
219 | |
220 | switch (component->identifier) { | |
221 | case NVM_COMP_ID_OROM: | |
222 | case NVM_COMP_ID_NVM: | |
223 | case NVM_COMP_ID_NETLIST: | |
224 | break; | |
225 | default: | |
226 | dev_err(dev, "Unable to update due to a firmware component with unknown ID %u\n", | |
227 | component->identifier); | |
228 | NL_SET_ERR_MSG_MOD(extack, "Unable to update due to unknown firmware component"); | |
229 | return -EOPNOTSUPP; | |
230 | } | |
231 | ||
232 | length = struct_size(comp_tbl, cvs, component->version_len); | |
233 | comp_tbl = kzalloc(length, GFP_KERNEL); | |
234 | if (!comp_tbl) | |
235 | return -ENOMEM; | |
236 | ||
237 | comp_tbl->comp_class = cpu_to_le16(component->classification); | |
238 | comp_tbl->comp_id = cpu_to_le16(component->identifier); | |
239 | comp_tbl->comp_class_idx = FWU_COMP_CLASS_IDX_NOT_USE; | |
240 | comp_tbl->comp_cmp_stamp = cpu_to_le32(component->comparison_stamp); | |
241 | comp_tbl->cvs_type = component->version_type; | |
242 | comp_tbl->cvs_len = component->version_len; | |
243 | memcpy(comp_tbl->cvs, component->version_string, component->version_len); | |
244 | ||
1e8249cc JK |
245 | dev_dbg(dev, "Sending component table to firmware:\n"); |
246 | ||
d69ea414 JK |
247 | status = ice_nvm_pass_component_tbl(hw, (u8 *)comp_tbl, length, |
248 | transfer_flag, &comp_response, | |
249 | &comp_response_code, NULL); | |
250 | ||
251 | kfree(comp_tbl); | |
252 | ||
253 | if (status) { | |
5f87ec48 | 254 | dev_err(dev, "Failed to transfer component table to firmware, err %d aq_err %s\n", |
5518ac2a | 255 | status, ice_aq_str(hw->adminq.sq_last_status)); |
d69ea414 JK |
256 | NL_SET_ERR_MSG_MOD(extack, "Failed to transfer component table to firmware"); |
257 | return -EIO; | |
258 | } | |
259 | ||
260 | return ice_check_component_response(pf, component->identifier, comp_response, | |
261 | comp_response_code, extack); | |
262 | } | |
263 | ||
264 | /** | |
265 | * ice_write_one_nvm_block - Write an NVM block and await completion response | |
266 | * @pf: the PF data structure | |
267 | * @module: the module to write to | |
268 | * @offset: offset in bytes | |
269 | * @block_size: size of the block to write, up to 4k | |
270 | * @block: pointer to block of data to write | |
271 | * @last_cmd: whether this is the last command | |
399e27db | 272 | * @reset_level: storage for reset level required |
d69ea414 JK |
273 | * @extack: netlink extended ACK structure |
274 | * | |
275 | * Write a block of data to a flash module, and await for the completion | |
276 | * response message from firmware. | |
277 | * | |
278 | * Note this function assumes the caller has acquired the NVM resource. | |
279 | * | |
399e27db JK |
280 | * On successful return, reset level indicates the device reset required to |
281 | * complete the update. | |
282 | * | |
283 | * 0 - ICE_AQC_NVM_POR_FLAG - A full power on is required | |
284 | * 1 - ICE_AQC_NVM_PERST_FLAG - A cold PCIe reset is required | |
285 | * 2 - ICE_AQC_NVM_EMPR_FLAG - An EMP reset is required | |
286 | * | |
d69ea414 JK |
287 | * Returns: zero on success, or a negative error code on failure. |
288 | */ | |
289 | static int | |
290 | ice_write_one_nvm_block(struct ice_pf *pf, u16 module, u32 offset, | |
291 | u16 block_size, u8 *block, bool last_cmd, | |
399e27db | 292 | u8 *reset_level, struct netlink_ext_ack *extack) |
d69ea414 JK |
293 | { |
294 | u16 completion_module, completion_retval; | |
295 | struct device *dev = ice_pf_to_dev(pf); | |
296 | struct ice_rq_event_info event; | |
297 | struct ice_hw *hw = &pf->hw; | |
d69ea414 JK |
298 | u32 completion_offset; |
299 | int err; | |
300 | ||
301 | memset(&event, 0, sizeof(event)); | |
302 | ||
1e8249cc JK |
303 | dev_dbg(dev, "Writing block of %u bytes for module 0x%02x at offset %u\n", |
304 | block_size, module, offset); | |
305 | ||
2ccc1c1c TN |
306 | err = ice_aq_update_nvm(hw, module, offset, block_size, block, |
307 | last_cmd, 0, NULL); | |
308 | if (err) { | |
5f87ec48 | 309 | dev_err(dev, "Failed to flash module 0x%02x with block of size %u at offset %u, err %d aq_err %s\n", |
2ccc1c1c | 310 | module, block_size, offset, err, |
d69ea414 JK |
311 | ice_aq_str(hw->adminq.sq_last_status)); |
312 | NL_SET_ERR_MSG_MOD(extack, "Failed to program flash module"); | |
313 | return -EIO; | |
314 | } | |
315 | ||
0ec86e8e JK |
316 | /* In most cases, firmware reports a write completion within a few |
317 | * milliseconds. However, it has been observed that a completion might | |
318 | * take more than a second to complete in some cases. The timeout here | |
319 | * is conservative and is intended to prevent failure to update when | |
320 | * firmware is slow to respond. | |
321 | */ | |
322 | err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write, 15 * HZ, &event); | |
d69ea414 | 323 | if (err) { |
1e8249cc JK |
324 | dev_err(dev, "Timed out while trying to flash module 0x%02x with block of size %u at offset %u, err %d\n", |
325 | module, block_size, offset, err); | |
d69ea414 JK |
326 | NL_SET_ERR_MSG_MOD(extack, "Timed out waiting for firmware"); |
327 | return -EIO; | |
328 | } | |
329 | ||
330 | completion_module = le16_to_cpu(event.desc.params.nvm.module_typeid); | |
331 | completion_retval = le16_to_cpu(event.desc.retval); | |
332 | ||
333 | completion_offset = le16_to_cpu(event.desc.params.nvm.offset_low); | |
334 | completion_offset |= event.desc.params.nvm.offset_high << 16; | |
335 | ||
336 | if (completion_module != module) { | |
337 | dev_err(dev, "Unexpected module_typeid in write completion: got 0x%x, expected 0x%x\n", | |
338 | completion_module, module); | |
339 | NL_SET_ERR_MSG_MOD(extack, "Unexpected firmware response"); | |
340 | return -EIO; | |
341 | } | |
342 | ||
343 | if (completion_offset != offset) { | |
344 | dev_err(dev, "Unexpected offset in write completion: got %u, expected %u\n", | |
345 | completion_offset, offset); | |
346 | NL_SET_ERR_MSG_MOD(extack, "Unexpected firmware response"); | |
347 | return -EIO; | |
348 | } | |
349 | ||
350 | if (completion_retval) { | |
1e8249cc JK |
351 | dev_err(dev, "Firmware failed to flash module 0x%02x with block of size %u at offset %u, err %s\n", |
352 | module, block_size, offset, | |
d69ea414 JK |
353 | ice_aq_str((enum ice_aq_err)completion_retval)); |
354 | NL_SET_ERR_MSG_MOD(extack, "Firmware failed to program flash module"); | |
355 | return -EIO; | |
356 | } | |
357 | ||
399e27db JK |
358 | /* For the last command to write the NVM bank, newer versions of |
359 | * firmware indicate the required level of reset to complete | |
360 | * activation of firmware. If the firmware supports this, cache the | |
361 | * response for indicating to the user later. Otherwise, assume that | |
362 | * a full power cycle is required. | |
363 | */ | |
364 | if (reset_level && last_cmd && module == ICE_SR_1ST_NVM_BANK_PTR) { | |
365 | if (hw->dev_caps.common_cap.pcie_reset_avoidance) { | |
366 | *reset_level = (event.desc.params.nvm.cmd_flags & | |
367 | ICE_AQC_NVM_RESET_LVL_M); | |
368 | dev_dbg(dev, "Firmware reported required reset level as %u\n", | |
369 | *reset_level); | |
370 | } else { | |
371 | *reset_level = ICE_AQC_NVM_POR_FLAG; | |
372 | dev_dbg(dev, "Firmware doesn't support indicating required reset level. Assuming a power cycle is required\n"); | |
373 | } | |
374 | } | |
375 | ||
d69ea414 JK |
376 | return 0; |
377 | } | |
378 | ||
379 | /** | |
380 | * ice_write_nvm_module - Write data to an NVM module | |
381 | * @pf: the PF driver structure | |
382 | * @module: the module id to program | |
383 | * @component: the name of the component being updated | |
384 | * @image: buffer of image data to write to the NVM | |
385 | * @length: length of the buffer | |
399e27db | 386 | * @reset_level: storage for reset level required |
d69ea414 JK |
387 | * @extack: netlink extended ACK structure |
388 | * | |
389 | * Loop over the data for a given NVM module and program it in 4 Kb | |
390 | * blocks. Notify devlink core of progress after each block is programmed. | |
391 | * Loops over a block of data and programs the NVM in 4k block chunks. | |
392 | * | |
393 | * Note this function assumes the caller has acquired the NVM resource. | |
394 | * | |
395 | * Returns: zero on success, or a negative error code on failure. | |
396 | */ | |
397 | static int | |
398 | ice_write_nvm_module(struct ice_pf *pf, u16 module, const char *component, | |
399e27db | 399 | const u8 *image, u32 length, u8 *reset_level, |
d69ea414 JK |
400 | struct netlink_ext_ack *extack) |
401 | { | |
1e8249cc | 402 | struct device *dev = ice_pf_to_dev(pf); |
d69ea414 JK |
403 | struct devlink *devlink; |
404 | u32 offset = 0; | |
405 | bool last_cmd; | |
406 | u8 *block; | |
407 | int err; | |
408 | ||
1e8249cc JK |
409 | dev_dbg(dev, "Beginning write of flash component '%s', module 0x%02x\n", component, module); |
410 | ||
d69ea414 JK |
411 | devlink = priv_to_devlink(pf); |
412 | ||
413 | devlink_flash_update_status_notify(devlink, "Flashing", | |
414 | component, 0, length); | |
415 | ||
416 | block = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL); | |
417 | if (!block) | |
418 | return -ENOMEM; | |
419 | ||
420 | do { | |
421 | u32 block_size; | |
422 | ||
423 | block_size = min_t(u32, ICE_AQ_MAX_BUF_LEN, length - offset); | |
424 | last_cmd = !(offset + block_size < length); | |
425 | ||
426 | /* ice_aq_update_nvm may copy the firmware response into the | |
427 | * buffer, so we must make a copy since the source data is | |
428 | * constant. | |
429 | */ | |
430 | memcpy(block, image + offset, block_size); | |
431 | ||
432 | err = ice_write_one_nvm_block(pf, module, offset, block_size, | |
399e27db JK |
433 | block, last_cmd, reset_level, |
434 | extack); | |
d69ea414 JK |
435 | if (err) |
436 | break; | |
437 | ||
438 | offset += block_size; | |
439 | ||
440 | devlink_flash_update_status_notify(devlink, "Flashing", | |
441 | component, offset, length); | |
442 | } while (!last_cmd); | |
443 | ||
1e8249cc JK |
444 | dev_dbg(dev, "Completed write of flash component '%s', module 0x%02x\n", component, module); |
445 | ||
d69ea414 JK |
446 | if (err) |
447 | devlink_flash_update_status_notify(devlink, "Flashing failed", | |
448 | component, length, length); | |
449 | else | |
450 | devlink_flash_update_status_notify(devlink, "Flashing done", | |
451 | component, length, length); | |
452 | ||
453 | kfree(block); | |
454 | return err; | |
455 | } | |
456 | ||
08e1294d JK |
457 | /* Length in seconds to wait before timing out when erasing a flash module. |
458 | * Yes, erasing really can take minutes to complete. | |
459 | */ | |
460 | #define ICE_FW_ERASE_TIMEOUT 300 | |
461 | ||
d69ea414 JK |
462 | /** |
463 | * ice_erase_nvm_module - Erase an NVM module and await firmware completion | |
464 | * @pf: the PF data structure | |
465 | * @module: the module to erase | |
466 | * @component: name of the component being updated | |
467 | * @extack: netlink extended ACK structure | |
468 | * | |
469 | * Erase the inactive NVM bank associated with this module, and await for | |
470 | * a completion response message from firmware. | |
471 | * | |
472 | * Note this function assumes the caller has acquired the NVM resource. | |
473 | * | |
474 | * Returns: zero on success, or a negative error code on failure. | |
475 | */ | |
476 | static int | |
477 | ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component, | |
478 | struct netlink_ext_ack *extack) | |
479 | { | |
480 | u16 completion_module, completion_retval; | |
481 | struct device *dev = ice_pf_to_dev(pf); | |
482 | struct ice_rq_event_info event; | |
483 | struct ice_hw *hw = &pf->hw; | |
484 | struct devlink *devlink; | |
d69ea414 JK |
485 | int err; |
486 | ||
1e8249cc JK |
487 | dev_dbg(dev, "Beginning erase of flash component '%s', module 0x%02x\n", component, module); |
488 | ||
d69ea414 JK |
489 | memset(&event, 0, sizeof(event)); |
490 | ||
491 | devlink = priv_to_devlink(pf); | |
492 | ||
08e1294d | 493 | devlink_flash_update_timeout_notify(devlink, "Erasing", component, ICE_FW_ERASE_TIMEOUT); |
d69ea414 | 494 | |
2ccc1c1c TN |
495 | err = ice_aq_erase_nvm(hw, module, NULL); |
496 | if (err) { | |
5f87ec48 | 497 | dev_err(dev, "Failed to erase %s (module 0x%02x), err %d aq_err %s\n", |
2ccc1c1c | 498 | component, module, err, |
d69ea414 JK |
499 | ice_aq_str(hw->adminq.sq_last_status)); |
500 | NL_SET_ERR_MSG_MOD(extack, "Failed to erase flash module"); | |
501 | err = -EIO; | |
502 | goto out_notify_devlink; | |
503 | } | |
504 | ||
08e1294d | 505 | err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_erase, ICE_FW_ERASE_TIMEOUT * HZ, &event); |
d69ea414 JK |
506 | if (err) { |
507 | dev_err(dev, "Timed out waiting for firmware to respond with erase completion for %s (module 0x%02x), err %d\n", | |
508 | component, module, err); | |
509 | NL_SET_ERR_MSG_MOD(extack, "Timed out waiting for firmware"); | |
510 | goto out_notify_devlink; | |
511 | } | |
512 | ||
513 | completion_module = le16_to_cpu(event.desc.params.nvm.module_typeid); | |
514 | completion_retval = le16_to_cpu(event.desc.retval); | |
515 | ||
516 | if (completion_module != module) { | |
517 | dev_err(dev, "Unexpected module_typeid in erase completion for %s: got 0x%x, expected 0x%x\n", | |
518 | component, completion_module, module); | |
519 | NL_SET_ERR_MSG_MOD(extack, "Unexpected firmware response"); | |
520 | err = -EIO; | |
521 | goto out_notify_devlink; | |
522 | } | |
523 | ||
524 | if (completion_retval) { | |
525 | dev_err(dev, "Firmware failed to erase %s (module 0x02%x), aq_err %s\n", | |
526 | component, module, | |
527 | ice_aq_str((enum ice_aq_err)completion_retval)); | |
528 | NL_SET_ERR_MSG_MOD(extack, "Firmware failed to erase flash"); | |
529 | err = -EIO; | |
530 | goto out_notify_devlink; | |
531 | } | |
532 | ||
1e8249cc JK |
533 | dev_dbg(dev, "Completed erase of flash component '%s', module 0x%02x\n", component, module); |
534 | ||
d69ea414 JK |
535 | out_notify_devlink: |
536 | if (err) | |
537 | devlink_flash_update_status_notify(devlink, "Erasing failed", | |
538 | component, 0, 0); | |
539 | else | |
540 | devlink_flash_update_status_notify(devlink, "Erasing done", | |
541 | component, 0, 0); | |
542 | ||
543 | return err; | |
544 | } | |
545 | ||
546 | /** | |
547 | * ice_switch_flash_banks - Tell firmware to switch NVM banks | |
548 | * @pf: Pointer to the PF data structure | |
549 | * @activate_flags: flags used for the activation command | |
399e27db | 550 | * @emp_reset_available: on return, indicates if EMP reset is available |
d69ea414 JK |
551 | * @extack: netlink extended ACK structure |
552 | * | |
553 | * Notify firmware to activate the newly written flash banks, and wait for the | |
554 | * firmware response. | |
555 | * | |
556 | * Returns: zero on success or an error code on failure. | |
557 | */ | |
399e27db JK |
558 | static int |
559 | ice_switch_flash_banks(struct ice_pf *pf, u8 activate_flags, | |
560 | u8 *emp_reset_available, struct netlink_ext_ack *extack) | |
d69ea414 JK |
561 | { |
562 | struct device *dev = ice_pf_to_dev(pf); | |
563 | struct ice_rq_event_info event; | |
564 | struct ice_hw *hw = &pf->hw; | |
d69ea414 | 565 | u16 completion_retval; |
399e27db | 566 | u8 response_flags; |
d69ea414 JK |
567 | int err; |
568 | ||
569 | memset(&event, 0, sizeof(event)); | |
570 | ||
399e27db | 571 | err = ice_nvm_write_activate(hw, activate_flags, &response_flags); |
2ccc1c1c | 572 | if (err) { |
5f87ec48 | 573 | dev_err(dev, "Failed to switch active flash banks, err %d aq_err %s\n", |
2ccc1c1c | 574 | err, ice_aq_str(hw->adminq.sq_last_status)); |
d69ea414 JK |
575 | NL_SET_ERR_MSG_MOD(extack, "Failed to switch active flash banks"); |
576 | return -EIO; | |
577 | } | |
578 | ||
399e27db JK |
579 | /* Newer versions of firmware have support to indicate whether an EMP |
580 | * reset to reload firmware is available. For older firmware, EMP | |
581 | * reset is always available. | |
582 | */ | |
583 | if (emp_reset_available) { | |
584 | if (hw->dev_caps.common_cap.reset_restrict_support) { | |
585 | *emp_reset_available = response_flags & ICE_AQC_NVM_EMPR_ENA; | |
586 | dev_dbg(dev, "Firmware indicated that EMP reset is %s\n", | |
587 | *emp_reset_available ? | |
588 | "available" : "not available"); | |
589 | } else { | |
590 | *emp_reset_available = ICE_AQC_NVM_EMPR_ENA; | |
591 | dev_dbg(dev, "Firmware does not support restricting EMP reset availability\n"); | |
592 | } | |
593 | } | |
594 | ||
0ec86e8e | 595 | err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_write_activate, 30 * HZ, |
d69ea414 JK |
596 | &event); |
597 | if (err) { | |
598 | dev_err(dev, "Timed out waiting for firmware to switch active flash banks, err %d\n", | |
599 | err); | |
600 | NL_SET_ERR_MSG_MOD(extack, "Timed out waiting for firmware"); | |
601 | return err; | |
602 | } | |
603 | ||
604 | completion_retval = le16_to_cpu(event.desc.retval); | |
605 | if (completion_retval) { | |
606 | dev_err(dev, "Firmware failed to switch active flash banks aq_err %s\n", | |
607 | ice_aq_str((enum ice_aq_err)completion_retval)); | |
608 | NL_SET_ERR_MSG_MOD(extack, "Firmware failed to switch active flash banks"); | |
609 | return -EIO; | |
610 | } | |
611 | ||
612 | return 0; | |
613 | } | |
614 | ||
615 | /** | |
616 | * ice_flash_component - Flash a component of the NVM | |
617 | * @context: PLDM fw update structure | |
618 | * @component: the component table to program | |
619 | * | |
620 | * Program the flash contents for a given component. First, determine the | |
621 | * module id. Then, erase the secondary bank for this module. Finally, write | |
622 | * the contents of the component to the NVM. | |
623 | * | |
624 | * Note this function assumes the caller has acquired the NVM resource. | |
625 | * | |
626 | * Returns: zero on success, or a negative error code on failure. | |
627 | */ | |
628 | static int | |
629 | ice_flash_component(struct pldmfw *context, struct pldmfw_component *component) | |
630 | { | |
631 | struct ice_fwu_priv *priv = container_of(context, struct ice_fwu_priv, context); | |
632 | struct netlink_ext_ack *extack = priv->extack; | |
633 | struct ice_pf *pf = priv->pf; | |
634 | const char *name; | |
399e27db | 635 | u8 *reset_level; |
d69ea414 JK |
636 | u16 module; |
637 | u8 flag; | |
638 | int err; | |
639 | ||
640 | switch (component->identifier) { | |
641 | case NVM_COMP_ID_OROM: | |
642 | module = ICE_SR_1ST_OROM_BANK_PTR; | |
643 | flag = ICE_AQC_NVM_ACTIV_SEL_OROM; | |
399e27db | 644 | reset_level = NULL; |
d69ea414 JK |
645 | name = "fw.undi"; |
646 | break; | |
647 | case NVM_COMP_ID_NVM: | |
648 | module = ICE_SR_1ST_NVM_BANK_PTR; | |
649 | flag = ICE_AQC_NVM_ACTIV_SEL_NVM; | |
399e27db | 650 | reset_level = &priv->reset_level; |
d69ea414 JK |
651 | name = "fw.mgmt"; |
652 | break; | |
653 | case NVM_COMP_ID_NETLIST: | |
654 | module = ICE_SR_NETLIST_BANK_PTR; | |
655 | flag = ICE_AQC_NVM_ACTIV_SEL_NETLIST; | |
399e27db | 656 | reset_level = NULL; |
d69ea414 JK |
657 | name = "fw.netlist"; |
658 | break; | |
659 | default: | |
660 | /* This should not trigger, since we check the id before | |
661 | * sending the component table to firmware. | |
662 | */ | |
663 | WARN(1, "Unexpected unknown component identifier 0x%02x", | |
664 | component->identifier); | |
665 | return -EINVAL; | |
666 | } | |
667 | ||
668 | /* Mark this component for activating at the end */ | |
669 | priv->activate_flags |= flag; | |
670 | ||
671 | err = ice_erase_nvm_module(pf, module, name, extack); | |
672 | if (err) | |
673 | return err; | |
674 | ||
675 | return ice_write_nvm_module(pf, module, name, component->component_data, | |
399e27db JK |
676 | component->component_size, reset_level, |
677 | extack); | |
d69ea414 JK |
678 | } |
679 | ||
680 | /** | |
681 | * ice_finalize_update - Perform last steps to complete device update | |
682 | * @context: PLDM fw update structure | |
683 | * | |
684 | * Called as the last step of the update process. Complete the update by | |
685 | * telling the firmware to switch active banks, and perform a reset of | |
686 | * configured. | |
687 | * | |
688 | * Returns: 0 on success, or an error code on failure. | |
689 | */ | |
690 | static int ice_finalize_update(struct pldmfw *context) | |
691 | { | |
692 | struct ice_fwu_priv *priv = container_of(context, struct ice_fwu_priv, context); | |
693 | struct netlink_ext_ack *extack = priv->extack; | |
694 | struct ice_pf *pf = priv->pf; | |
399e27db JK |
695 | struct devlink *devlink; |
696 | int err; | |
d69ea414 JK |
697 | |
698 | /* Finally, notify firmware to activate the written NVM banks */ | |
399e27db JK |
699 | err = ice_switch_flash_banks(pf, priv->activate_flags, |
700 | &priv->emp_reset_available, extack); | |
701 | if (err) | |
702 | return err; | |
703 | ||
704 | devlink = priv_to_devlink(pf); | |
705 | ||
706 | /* If the required reset is EMPR, but EMPR is disabled, report that | |
707 | * a reboot is required instead. | |
708 | */ | |
709 | if (priv->reset_level == ICE_AQC_NVM_EMPR_FLAG && | |
710 | !priv->emp_reset_available) { | |
711 | dev_dbg(ice_pf_to_dev(pf), "Firmware indicated EMP reset as sufficient, but EMP reset is disabled\n"); | |
712 | priv->reset_level = ICE_AQC_NVM_PERST_FLAG; | |
713 | } | |
714 | ||
715 | switch (priv->reset_level) { | |
716 | case ICE_AQC_NVM_EMPR_FLAG: | |
717 | devlink_flash_update_status_notify(devlink, | |
718 | "Activate new firmware by devlink reload", | |
719 | NULL, 0, 0); | |
720 | break; | |
721 | case ICE_AQC_NVM_PERST_FLAG: | |
722 | devlink_flash_update_status_notify(devlink, | |
723 | "Activate new firmware by rebooting the system", | |
724 | NULL, 0, 0); | |
725 | break; | |
726 | case ICE_AQC_NVM_POR_FLAG: | |
727 | default: | |
728 | devlink_flash_update_status_notify(devlink, | |
729 | "Activate new firmware by power cycling the system", | |
730 | NULL, 0, 0); | |
731 | break; | |
732 | } | |
733 | ||
734 | pf->fw_emp_reset_disabled = !priv->emp_reset_available; | |
735 | ||
736 | return 0; | |
d69ea414 JK |
737 | } |
738 | ||
f52d1668 PSJ |
739 | struct ice_pldm_pci_record_id { |
740 | u32 vendor; | |
741 | u32 device; | |
742 | u32 subsystem_vendor; | |
743 | u32 subsystem_device; | |
744 | }; | |
745 | ||
746 | /** | |
747 | * ice_op_pci_match_record - Check if a PCI device matches the record | |
748 | * @context: PLDM fw update structure | |
749 | * @record: list of records extracted from the PLDM image | |
750 | * | |
751 | * Determine if the PCI device associated with this device matches the record | |
752 | * data provided. | |
753 | * | |
754 | * Searches the descriptor TLVs and extracts the relevant descriptor data into | |
755 | * a pldm_pci_record_id. This is then compared against the PCI device ID | |
756 | * information. | |
757 | * | |
758 | * Returns: true if the device matches the record, false otherwise. | |
759 | */ | |
760 | static bool | |
761 | ice_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record) | |
762 | { | |
763 | struct pci_dev *pdev = to_pci_dev(context->dev); | |
764 | struct ice_pldm_pci_record_id id = { | |
765 | .vendor = PCI_ANY_ID, | |
766 | .device = PCI_ANY_ID, | |
767 | .subsystem_vendor = PCI_ANY_ID, | |
768 | .subsystem_device = PCI_ANY_ID, | |
769 | }; | |
770 | struct pldmfw_desc_tlv *desc; | |
771 | ||
772 | list_for_each_entry(desc, &record->descs, entry) { | |
773 | u16 value; | |
774 | int *ptr; | |
775 | ||
776 | switch (desc->type) { | |
777 | case PLDM_DESC_ID_PCI_VENDOR_ID: | |
778 | ptr = &id.vendor; | |
779 | break; | |
780 | case PLDM_DESC_ID_PCI_DEVICE_ID: | |
781 | ptr = &id.device; | |
782 | break; | |
783 | case PLDM_DESC_ID_PCI_SUBVENDOR_ID: | |
784 | ptr = &id.subsystem_vendor; | |
785 | break; | |
786 | case PLDM_DESC_ID_PCI_SUBDEV_ID: | |
787 | ptr = &id.subsystem_device; | |
788 | break; | |
789 | default: | |
790 | /* Skip unrelated TLVs */ | |
791 | continue; | |
792 | } | |
793 | ||
794 | value = get_unaligned_le16(desc->data); | |
795 | /* A value of zero for one of the descriptors is sometimes | |
796 | * used when the record should ignore this field when matching | |
797 | * device. For example if the record applies to any subsystem | |
798 | * device or vendor. | |
799 | */ | |
800 | if (value) | |
801 | *ptr = value; | |
802 | else | |
803 | *ptr = PCI_ANY_ID; | |
804 | } | |
805 | ||
806 | /* the E822 device can have a generic device ID so check for that */ | |
807 | if ((id.vendor == PCI_ANY_ID || id.vendor == pdev->vendor) && | |
808 | (id.device == PCI_ANY_ID || id.device == pdev->device || | |
809 | id.device == ICE_DEV_ID_E822_SI_DFLT) && | |
810 | (id.subsystem_vendor == PCI_ANY_ID || | |
811 | id.subsystem_vendor == pdev->subsystem_vendor) && | |
812 | (id.subsystem_device == PCI_ANY_ID || | |
813 | id.subsystem_device == pdev->subsystem_device)) | |
814 | return true; | |
815 | ||
816 | return false; | |
817 | } | |
818 | ||
819 | static const struct pldmfw_ops ice_fwu_ops_e810 = { | |
d69ea414 JK |
820 | .match_record = &pldmfw_op_pci_match_record, |
821 | .send_package_data = &ice_send_package_data, | |
822 | .send_component_table = &ice_send_component_table, | |
823 | .flash_component = &ice_flash_component, | |
824 | .finalize_update = &ice_finalize_update, | |
825 | }; | |
826 | ||
f52d1668 PSJ |
827 | static const struct pldmfw_ops ice_fwu_ops_e822 = { |
828 | .match_record = &ice_op_pci_match_record, | |
829 | .send_package_data = &ice_send_package_data, | |
830 | .send_component_table = &ice_send_component_table, | |
831 | .flash_component = &ice_flash_component, | |
832 | .finalize_update = &ice_finalize_update, | |
833 | }; | |
834 | ||
d69ea414 | 835 | /** |
399e27db | 836 | * ice_get_pending_updates - Check if the component has a pending update |
d69ea414 | 837 | * @pf: the PF driver structure |
399e27db JK |
838 | * @pending: on return, bitmap of updates pending |
839 | * @extack: Netlink extended ACK | |
d69ea414 | 840 | * |
399e27db | 841 | * Check if the device has any pending updates on any flash components. |
d69ea414 | 842 | * |
399e27db JK |
843 | * Returns: zero on success, or a negative error code on failure. Updates |
844 | * pending with the bitmap of pending updates. | |
d69ea414 | 845 | */ |
399e27db JK |
846 | int ice_get_pending_updates(struct ice_pf *pf, u8 *pending, |
847 | struct netlink_ext_ack *extack) | |
d69ea414 | 848 | { |
d69ea414 JK |
849 | struct device *dev = ice_pf_to_dev(pf); |
850 | struct ice_hw_dev_caps *dev_caps; | |
851 | struct ice_hw *hw = &pf->hw; | |
d69ea414 JK |
852 | int err; |
853 | ||
854 | dev_caps = kzalloc(sizeof(*dev_caps), GFP_KERNEL); | |
855 | if (!dev_caps) | |
856 | return -ENOMEM; | |
857 | ||
858 | /* Read the most recent device capabilities from firmware. Do not use | |
859 | * the cached values in hw->dev_caps, because the pending update flag | |
860 | * may have changed, e.g. if an update was previously completed and | |
861 | * the system has not yet rebooted. | |
862 | */ | |
2ccc1c1c TN |
863 | err = ice_discover_dev_caps(hw, dev_caps); |
864 | if (err) { | |
d69ea414 JK |
865 | NL_SET_ERR_MSG_MOD(extack, "Unable to read device capabilities"); |
866 | kfree(dev_caps); | |
c1484691 | 867 | return err; |
d69ea414 JK |
868 | } |
869 | ||
399e27db JK |
870 | *pending = 0; |
871 | ||
d69ea414 JK |
872 | if (dev_caps->common_cap.nvm_update_pending_nvm) { |
873 | dev_info(dev, "The fw.mgmt flash component has a pending update\n"); | |
399e27db | 874 | *pending |= ICE_AQC_NVM_ACTIV_SEL_NVM; |
d69ea414 JK |
875 | } |
876 | ||
877 | if (dev_caps->common_cap.nvm_update_pending_orom) { | |
878 | dev_info(dev, "The fw.undi flash component has a pending update\n"); | |
399e27db | 879 | *pending |= ICE_AQC_NVM_ACTIV_SEL_OROM; |
d69ea414 JK |
880 | } |
881 | ||
882 | if (dev_caps->common_cap.nvm_update_pending_netlist) { | |
883 | dev_info(dev, "The fw.netlist flash component has a pending update\n"); | |
399e27db | 884 | *pending |= ICE_AQC_NVM_ACTIV_SEL_NETLIST; |
d69ea414 JK |
885 | } |
886 | ||
887 | kfree(dev_caps); | |
888 | ||
399e27db JK |
889 | return 0; |
890 | } | |
891 | ||
892 | /** | |
893 | * ice_cancel_pending_update - Cancel any pending update for a component | |
894 | * @pf: the PF driver structure | |
895 | * @component: if not NULL, the name of the component being updated | |
896 | * @extack: Netlink extended ACK structure | |
897 | * | |
898 | * Cancel any pending update for the specified component. If component is | |
899 | * NULL, all device updates will be canceled. | |
900 | * | |
901 | * Returns: zero on success, or a negative error code on failure. | |
902 | */ | |
903 | static int | |
904 | ice_cancel_pending_update(struct ice_pf *pf, const char *component, | |
905 | struct netlink_ext_ack *extack) | |
906 | { | |
907 | struct devlink *devlink = priv_to_devlink(pf); | |
908 | struct device *dev = ice_pf_to_dev(pf); | |
909 | struct ice_hw *hw = &pf->hw; | |
910 | u8 pending; | |
911 | int err; | |
912 | ||
913 | err = ice_get_pending_updates(pf, &pending, extack); | |
914 | if (err) | |
915 | return err; | |
916 | ||
d69ea414 JK |
917 | /* If the flash_update request is for a specific component, ignore all |
918 | * of the other components. | |
919 | */ | |
920 | if (component) { | |
921 | if (strcmp(component, "fw.mgmt") == 0) | |
922 | pending &= ICE_AQC_NVM_ACTIV_SEL_NVM; | |
923 | else if (strcmp(component, "fw.undi") == 0) | |
924 | pending &= ICE_AQC_NVM_ACTIV_SEL_OROM; | |
925 | else if (strcmp(component, "fw.netlist") == 0) | |
926 | pending &= ICE_AQC_NVM_ACTIV_SEL_NETLIST; | |
927 | else | |
928 | WARN(1, "Unexpected flash component %s", component); | |
929 | } | |
930 | ||
931 | /* There is no previous pending update, so this request may continue */ | |
932 | if (!pending) | |
933 | return 0; | |
934 | ||
935 | /* In order to allow overwriting a previous pending update, notify | |
936 | * firmware to cancel that update by issuing the appropriate command. | |
937 | */ | |
938 | devlink_flash_update_status_notify(devlink, | |
939 | "Canceling previous pending update", | |
940 | component, 0, 0); | |
941 | ||
2ccc1c1c TN |
942 | err = ice_acquire_nvm(hw, ICE_RES_WRITE); |
943 | if (err) { | |
5f87ec48 | 944 | dev_err(dev, "Failed to acquire device flash lock, err %d aq_err %s\n", |
2ccc1c1c | 945 | err, ice_aq_str(hw->adminq.sq_last_status)); |
d69ea414 | 946 | NL_SET_ERR_MSG_MOD(extack, "Failed to acquire device flash lock"); |
c1484691 | 947 | return err; |
d69ea414 JK |
948 | } |
949 | ||
950 | pending |= ICE_AQC_NVM_REVERT_LAST_ACTIV; | |
399e27db | 951 | err = ice_switch_flash_banks(pf, pending, NULL, extack); |
d69ea414 JK |
952 | |
953 | ice_release_nvm(hw); | |
954 | ||
399e27db JK |
955 | /* Since we've canceled the pending update, we no longer know if EMP |
956 | * reset is restricted. | |
957 | */ | |
958 | pf->fw_emp_reset_disabled = false; | |
959 | ||
d69ea414 JK |
960 | return err; |
961 | } | |
c356eaa8 JK |
962 | |
963 | /** | |
c9f7a483 JK |
964 | * ice_devlink_flash_update - Write a firmware image to the device |
965 | * @devlink: pointer to devlink associated with the device to update | |
966 | * @params: devlink flash update parameters | |
c356eaa8 JK |
967 | * @extack: netlink extended ACK structure |
968 | * | |
969 | * Parse the data for a given firmware file, verifying that it is a valid PLDM | |
970 | * formatted image that matches this device. | |
971 | * | |
972 | * Extract the device record Package Data and Component Tables and send them | |
973 | * to the firmware. Extract and write the flash data for each of the three | |
974 | * main flash components, "fw.mgmt", "fw.undi", and "fw.netlist". Notify | |
975 | * firmware once the data is written to the inactive banks. | |
976 | * | |
977 | * Returns: zero on success or a negative error code on failure. | |
978 | */ | |
c9f7a483 JK |
979 | int ice_devlink_flash_update(struct devlink *devlink, |
980 | struct devlink_flash_update_params *params, | |
981 | struct netlink_ext_ack *extack) | |
c356eaa8 | 982 | { |
c9f7a483 | 983 | struct ice_pf *pf = devlink_priv(devlink); |
c356eaa8 JK |
984 | struct device *dev = ice_pf_to_dev(pf); |
985 | struct ice_hw *hw = &pf->hw; | |
986 | struct ice_fwu_priv priv; | |
c9f7a483 | 987 | u8 preservation; |
c356eaa8 JK |
988 | int err; |
989 | ||
c9f7a483 JK |
990 | if (!params->overwrite_mask) { |
991 | /* preserve all settings and identifiers */ | |
992 | preservation = ICE_AQC_NVM_PRESERVE_ALL; | |
993 | } else if (params->overwrite_mask == DEVLINK_FLASH_OVERWRITE_SETTINGS) { | |
994 | /* overwrite settings, but preserve the vital device identifiers */ | |
995 | preservation = ICE_AQC_NVM_PRESERVE_SELECTED; | |
996 | } else if (params->overwrite_mask == (DEVLINK_FLASH_OVERWRITE_SETTINGS | | |
997 | DEVLINK_FLASH_OVERWRITE_IDENTIFIERS)) { | |
998 | /* overwrite both settings and identifiers, preserve nothing */ | |
999 | preservation = ICE_AQC_NVM_NO_PRESERVATION; | |
1000 | } else { | |
1001 | NL_SET_ERR_MSG_MOD(extack, "Requested overwrite mask is not supported"); | |
1002 | return -EOPNOTSUPP; | |
1003 | } | |
1004 | ||
1005 | if (!hw->dev_caps.common_cap.nvm_unified_update) { | |
1006 | NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update"); | |
1007 | return -EOPNOTSUPP; | |
c356eaa8 JK |
1008 | } |
1009 | ||
1010 | memset(&priv, 0, sizeof(priv)); | |
1011 | ||
f52d1668 PSJ |
1012 | /* the E822 device needs a slightly different ops */ |
1013 | if (hw->mac_type == ICE_MAC_GENERIC) | |
1014 | priv.context.ops = &ice_fwu_ops_e822; | |
1015 | else | |
1016 | priv.context.ops = &ice_fwu_ops_e810; | |
c356eaa8 JK |
1017 | priv.context.dev = dev; |
1018 | priv.extack = extack; | |
1019 | priv.pf = pf; | |
1020 | priv.activate_flags = preservation; | |
1021 | ||
c9f7a483 JK |
1022 | devlink_flash_update_status_notify(devlink, "Preparing to flash", NULL, 0, 0); |
1023 | ||
1024 | err = ice_cancel_pending_update(pf, NULL, extack); | |
1025 | if (err) | |
1026 | return err; | |
1027 | ||
c356eaa8 JK |
1028 | err = ice_acquire_nvm(hw, ICE_RES_WRITE); |
1029 | if (err) { | |
1030 | dev_err(dev, "Failed to acquire device flash lock, err %d aq_err %s\n", | |
1031 | err, ice_aq_str(hw->adminq.sq_last_status)); | |
1032 | NL_SET_ERR_MSG_MOD(extack, "Failed to acquire device flash lock"); | |
1033 | return err; | |
1034 | } | |
1035 | ||
c9f7a483 | 1036 | err = pldmfw_flash_image(&priv.context, params->fw); |
c356eaa8 JK |
1037 | if (err == -ENOENT) { |
1038 | dev_err(dev, "Firmware image has no record matching this device\n"); | |
1039 | NL_SET_ERR_MSG_MOD(extack, "Firmware image has no record matching this device"); | |
1040 | } else if (err) { | |
1041 | /* Do not set a generic extended ACK message here. A more | |
1042 | * specific message may already have been set by one of our | |
1043 | * ops. | |
1044 | */ | |
1045 | dev_err(dev, "Failed to flash PLDM image, err %d", err); | |
1046 | } | |
1047 | ||
1048 | ice_release_nvm(hw); | |
1049 | ||
1050 | return err; | |
1051 | } |