12bb3e103SShalom Toledo // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
22bb3e103SShalom Toledo /* Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved */
3410ed13cSYotam Gigi
4410ed13cSYotam Gigi #define pr_fmt(fmt) "mlxfw: " fmt
5410ed13cSYotam Gigi
6410ed13cSYotam Gigi #include <linux/kernel.h>
7410ed13cSYotam Gigi #include <linux/module.h>
8410ed13cSYotam Gigi #include <linux/delay.h>
9410ed13cSYotam Gigi
10410ed13cSYotam Gigi #include "mlxfw.h"
11410ed13cSYotam Gigi #include "mlxfw_mfa2.h"
12410ed13cSYotam Gigi
13410ed13cSYotam Gigi #define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200
14410ed13cSYotam Gigi #define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000
15410ed13cSYotam Gigi #define MLXFW_FSM_STATE_WAIT_ROUNDS \
16410ed13cSYotam Gigi (MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS)
17410ed13cSYotam Gigi
1886a1270fSSaeed Mahameed static const int mlxfw_fsm_state_errno[] = {
1986a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_ERROR] = -EIO,
2086a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = -EBADMSG,
2186a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = -ENOENT,
2286a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = -ENOKEY,
2386a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = -EACCES,
2486a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = -EKEYREVOKED,
2586a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = -EKEYREJECTED,
2686a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = -ENOEXEC,
2786a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = -EBUSY,
2886a1270fSSaeed Mahameed [MLXFW_FSM_STATE_ERR_MAX] = -EINVAL
2986a1270fSSaeed Mahameed };
3086a1270fSSaeed Mahameed
3186a1270fSSaeed Mahameed #define MLXFW_ERR_PRFX "Firmware flash failed: "
326a3f707cSSaeed Mahameed #define MLXFW_ERR_MSG(fwdev, extack, msg, err) do { \
336a3f707cSSaeed Mahameed mlxfw_err(fwdev, "%s, err (%d)\n", MLXFW_ERR_PRFX msg, err); \
3486a1270fSSaeed Mahameed NL_SET_ERR_MSG_MOD(extack, MLXFW_ERR_PRFX msg); \
3586a1270fSSaeed Mahameed } while (0)
3686a1270fSSaeed Mahameed
mlxfw_fsm_state_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,enum mlxfw_fsm_state_err err)376a3f707cSSaeed Mahameed static int mlxfw_fsm_state_err(struct mlxfw_dev *mlxfw_dev,
386a3f707cSSaeed Mahameed struct netlink_ext_ack *extack,
3986a1270fSSaeed Mahameed enum mlxfw_fsm_state_err err)
4086a1270fSSaeed Mahameed {
4186a1270fSSaeed Mahameed enum mlxfw_fsm_state_err fsm_state_err;
4286a1270fSSaeed Mahameed
4386a1270fSSaeed Mahameed fsm_state_err = min_t(enum mlxfw_fsm_state_err, err,
4486a1270fSSaeed Mahameed MLXFW_FSM_STATE_ERR_MAX);
4586a1270fSSaeed Mahameed
4686a1270fSSaeed Mahameed switch (fsm_state_err) {
4786a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_ERROR:
486a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "general error", err);
4986a1270fSSaeed Mahameed break;
5086a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR:
516a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "component hash mismatch", err);
5286a1270fSSaeed Mahameed break;
5386a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE:
546a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "component not applicable", err);
5586a1270fSSaeed Mahameed break;
5686a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY:
576a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown key", err);
5886a1270fSSaeed Mahameed break;
5986a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED:
606a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "authentication failed", err);
6186a1270fSSaeed Mahameed break;
6286a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED:
636a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "component was not signed", err);
6486a1270fSSaeed Mahameed break;
6586a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE:
666a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "key not applicable", err);
6786a1270fSSaeed Mahameed break;
6886a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT:
696a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "bad format", err);
7086a1270fSSaeed Mahameed break;
7186a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET:
726a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "pending reset", err);
7386a1270fSSaeed Mahameed break;
74*df561f66SGustavo A. R. Silva case MLXFW_FSM_STATE_ERR_OK:
7586a1270fSSaeed Mahameed case MLXFW_FSM_STATE_ERR_MAX:
766a3f707cSSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown error", err);
7786a1270fSSaeed Mahameed break;
7810395e99SZheng Bin }
7986a1270fSSaeed Mahameed
8086a1270fSSaeed Mahameed return mlxfw_fsm_state_errno[fsm_state_err];
81410ed13cSYotam Gigi };
82410ed13cSYotam Gigi
mlxfw_fsm_state_wait(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,enum mlxfw_fsm_state fsm_state,struct netlink_ext_ack * extack)83410ed13cSYotam Gigi static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
8444f18db5SJiri Pirko enum mlxfw_fsm_state fsm_state,
8544f18db5SJiri Pirko struct netlink_ext_ack *extack)
86410ed13cSYotam Gigi {
87410ed13cSYotam Gigi enum mlxfw_fsm_state_err fsm_state_err;
88410ed13cSYotam Gigi enum mlxfw_fsm_state curr_fsm_state;
89410ed13cSYotam Gigi int times;
90410ed13cSYotam Gigi int err;
91410ed13cSYotam Gigi
92410ed13cSYotam Gigi times = MLXFW_FSM_STATE_WAIT_ROUNDS;
93410ed13cSYotam Gigi retry:
94410ed13cSYotam Gigi err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
95410ed13cSYotam Gigi &curr_fsm_state, &fsm_state_err);
96f7fe7aa8SSaeed Mahameed if (err) {
975042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM state query failed", err);
98410ed13cSYotam Gigi return err;
99f7fe7aa8SSaeed Mahameed }
100410ed13cSYotam Gigi
10186a1270fSSaeed Mahameed if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK)
1026a3f707cSSaeed Mahameed return mlxfw_fsm_state_err(mlxfw_dev, extack, fsm_state_err);
10386a1270fSSaeed Mahameed
104410ed13cSYotam Gigi if (curr_fsm_state != fsm_state) {
105410ed13cSYotam Gigi if (--times == 0) {
1065042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
1075042e8b9SSaeed Mahameed "Timeout reached on FSM state change", -ETIMEDOUT);
108410ed13cSYotam Gigi return -ETIMEDOUT;
109410ed13cSYotam Gigi }
110410ed13cSYotam Gigi msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
111410ed13cSYotam Gigi goto retry;
112410ed13cSYotam Gigi }
113410ed13cSYotam Gigi return 0;
114410ed13cSYotam Gigi }
115410ed13cSYotam Gigi
116958dfd0dSEran Ben Elisha static int
mlxfw_fsm_reactivate_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,u8 err)117958dfd0dSEran Ben Elisha mlxfw_fsm_reactivate_err(struct mlxfw_dev *mlxfw_dev,
118958dfd0dSEran Ben Elisha struct netlink_ext_ack *extack, u8 err)
119958dfd0dSEran Ben Elisha {
120958dfd0dSEran Ben Elisha enum mlxfw_fsm_reactivate_status status;
121958dfd0dSEran Ben Elisha
122958dfd0dSEran Ben Elisha #define MXFW_REACT_PRFX "Reactivate FSM: "
123958dfd0dSEran Ben Elisha #define MLXFW_REACT_ERR(msg, err) \
124958dfd0dSEran Ben Elisha MLXFW_ERR_MSG(mlxfw_dev, extack, MXFW_REACT_PRFX msg, err)
125958dfd0dSEran Ben Elisha
126958dfd0dSEran Ben Elisha status = min_t(enum mlxfw_fsm_reactivate_status, err,
127958dfd0dSEran Ben Elisha MLXFW_FSM_REACTIVATE_STATUS_MAX);
128958dfd0dSEran Ben Elisha
129958dfd0dSEran Ben Elisha switch (status) {
130958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_BUSY:
131958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("busy", err);
132958dfd0dSEran Ben Elisha break;
133958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_PROHIBITED_FW_VER_ERR:
134958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("prohibited fw ver", err);
135958dfd0dSEran Ben Elisha break;
136958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_COPY_FAILED:
137958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("first page copy failed", err);
138958dfd0dSEran Ben Elisha break;
139958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_ERASE_FAILED:
140958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("first page erase failed", err);
141958dfd0dSEran Ben Elisha break;
142958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_RESTORE_FAILED:
143958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("first page restore failed", err);
144958dfd0dSEran Ben Elisha break;
145958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_CANDIDATE_FW_DEACTIVATION_FAILED:
146958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("candidate fw deactivation failed", err);
147958dfd0dSEran Ben Elisha break;
148958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_ERR_DEVICE_RESET_REQUIRED:
149958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("device reset required", err);
150958dfd0dSEran Ben Elisha break;
151958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_ERR_FW_PROGRAMMING_NEEDED:
152f2ce925aSColin Ian King MLXFW_REACT_ERR("fw programming needed", err);
153958dfd0dSEran Ben Elisha break;
154958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED:
155958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("fw already activated", err);
156958dfd0dSEran Ben Elisha break;
157*df561f66SGustavo A. R. Silva case MLXFW_FSM_REACTIVATE_STATUS_OK:
158958dfd0dSEran Ben Elisha case MLXFW_FSM_REACTIVATE_STATUS_MAX:
159958dfd0dSEran Ben Elisha MLXFW_REACT_ERR("unexpected error", err);
160958dfd0dSEran Ben Elisha break;
16110395e99SZheng Bin }
162958dfd0dSEran Ben Elisha return -EREMOTEIO;
163958dfd0dSEran Ben Elisha };
164958dfd0dSEran Ben Elisha
mlxfw_fsm_reactivate(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,bool * supported)165958dfd0dSEran Ben Elisha static int mlxfw_fsm_reactivate(struct mlxfw_dev *mlxfw_dev,
166958dfd0dSEran Ben Elisha struct netlink_ext_ack *extack,
167958dfd0dSEran Ben Elisha bool *supported)
168958dfd0dSEran Ben Elisha {
169958dfd0dSEran Ben Elisha u8 status;
170958dfd0dSEran Ben Elisha int err;
171958dfd0dSEran Ben Elisha
172958dfd0dSEran Ben Elisha if (!mlxfw_dev->ops->fsm_reactivate)
173958dfd0dSEran Ben Elisha return 0;
174958dfd0dSEran Ben Elisha
175958dfd0dSEran Ben Elisha err = mlxfw_dev->ops->fsm_reactivate(mlxfw_dev, &status);
176958dfd0dSEran Ben Elisha if (err == -EOPNOTSUPP) {
177958dfd0dSEran Ben Elisha *supported = false;
178958dfd0dSEran Ben Elisha return 0;
179958dfd0dSEran Ben Elisha }
180958dfd0dSEran Ben Elisha
181958dfd0dSEran Ben Elisha if (err) {
182958dfd0dSEran Ben Elisha MLXFW_ERR_MSG(mlxfw_dev, extack,
183958dfd0dSEran Ben Elisha "Could not reactivate firmware flash", err);
184958dfd0dSEran Ben Elisha return err;
185958dfd0dSEran Ben Elisha }
186958dfd0dSEran Ben Elisha
187958dfd0dSEran Ben Elisha if (status == MLXFW_FSM_REACTIVATE_STATUS_OK ||
188958dfd0dSEran Ben Elisha status == MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED)
189958dfd0dSEran Ben Elisha return 0;
190958dfd0dSEran Ben Elisha
191958dfd0dSEran Ben Elisha return mlxfw_fsm_reactivate_err(mlxfw_dev, extack, status);
192958dfd0dSEran Ben Elisha }
193958dfd0dSEran Ben Elisha
mlxfw_status_notify(struct mlxfw_dev * mlxfw_dev,const char * msg,const char * comp_name,u32 done_bytes,u32 total_bytes)1944ae57566SSaeed Mahameed static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev,
1954ae57566SSaeed Mahameed const char *msg, const char *comp_name,
1964ae57566SSaeed Mahameed u32 done_bytes, u32 total_bytes)
1974ae57566SSaeed Mahameed {
1984ae57566SSaeed Mahameed devlink_flash_update_status_notify(mlxfw_dev->devlink, msg, comp_name,
1994ae57566SSaeed Mahameed done_bytes, total_bytes);
2004ae57566SSaeed Mahameed }
2014ae57566SSaeed Mahameed
202410ed13cSYotam Gigi #define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
203410ed13cSYotam Gigi #define MLXFW_ALIGN_UP(x, align_bits) \
204410ed13cSYotam Gigi MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
205410ed13cSYotam Gigi
mlxfw_flash_component(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_component * comp,bool reactivate_supp,struct netlink_ext_ack * extack)206410ed13cSYotam Gigi static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
207410ed13cSYotam Gigi u32 fwhandle,
20844f18db5SJiri Pirko struct mlxfw_mfa2_component *comp,
209958dfd0dSEran Ben Elisha bool reactivate_supp,
21044f18db5SJiri Pirko struct netlink_ext_ack *extack)
211410ed13cSYotam Gigi {
212410ed13cSYotam Gigi u16 comp_max_write_size;
213410ed13cSYotam Gigi u8 comp_align_bits;
214410ed13cSYotam Gigi u32 comp_max_size;
2155853c418SJiri Pirko char comp_name[8];
216410ed13cSYotam Gigi u16 block_size;
217410ed13cSYotam Gigi u8 *block_ptr;
218410ed13cSYotam Gigi u32 offset;
219410ed13cSYotam Gigi int err;
220410ed13cSYotam Gigi
2215853c418SJiri Pirko sprintf(comp_name, "%u", comp->index);
2225853c418SJiri Pirko
223410ed13cSYotam Gigi err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
224410ed13cSYotam Gigi &comp_max_size, &comp_align_bits,
225410ed13cSYotam Gigi &comp_max_write_size);
226f7fe7aa8SSaeed Mahameed if (err) {
2275042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM component query failed", err);
228410ed13cSYotam Gigi return err;
229f7fe7aa8SSaeed Mahameed }
230410ed13cSYotam Gigi
231410ed13cSYotam Gigi if (comp->data_size > comp_max_size) {
2325042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
2335042e8b9SSaeed Mahameed "Component size is bigger than limit", -EINVAL);
234410ed13cSYotam Gigi return -EINVAL;
235410ed13cSYotam Gigi }
236410ed13cSYotam Gigi
237410ed13cSYotam Gigi comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
238410ed13cSYotam Gigi comp_align_bits);
239410ed13cSYotam Gigi
2406a3f707cSSaeed Mahameed mlxfw_dbg(mlxfw_dev, "Component update\n");
2415853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0);
242410ed13cSYotam Gigi err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
243410ed13cSYotam Gigi comp->index,
244410ed13cSYotam Gigi comp->data_size);
245f7fe7aa8SSaeed Mahameed if (err) {
246958dfd0dSEran Ben Elisha if (!reactivate_supp)
247958dfd0dSEran Ben Elisha MLXFW_ERR_MSG(mlxfw_dev, extack,
248958dfd0dSEran Ben Elisha "FSM component update failed, FW reactivate is not supported",
249958dfd0dSEran Ben Elisha err);
250958dfd0dSEran Ben Elisha else
2515042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
2525042e8b9SSaeed Mahameed "FSM component update failed", err);
253410ed13cSYotam Gigi return err;
254f7fe7aa8SSaeed Mahameed }
255410ed13cSYotam Gigi
256410ed13cSYotam Gigi err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
25744f18db5SJiri Pirko MLXFW_FSM_STATE_DOWNLOAD, extack);
258410ed13cSYotam Gigi if (err)
259410ed13cSYotam Gigi goto err_out;
260410ed13cSYotam Gigi
2616a3f707cSSaeed Mahameed mlxfw_dbg(mlxfw_dev, "Component download\n");
2625853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Downloading component",
2635853c418SJiri Pirko comp_name, 0, comp->data_size);
264410ed13cSYotam Gigi for (offset = 0;
265410ed13cSYotam Gigi offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
266410ed13cSYotam Gigi offset += comp_max_write_size) {
267410ed13cSYotam Gigi block_ptr = comp->data + offset;
268410ed13cSYotam Gigi block_size = (u16) min_t(u32, comp->data_size - offset,
269410ed13cSYotam Gigi comp_max_write_size);
270410ed13cSYotam Gigi err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
271410ed13cSYotam Gigi block_ptr, block_size,
272410ed13cSYotam Gigi offset);
273f7fe7aa8SSaeed Mahameed if (err) {
2745042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
2755042e8b9SSaeed Mahameed "Component download failed", err);
276410ed13cSYotam Gigi goto err_out;
277f7fe7aa8SSaeed Mahameed }
2785853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Downloading component",
2795853c418SJiri Pirko comp_name, offset + block_size,
2805853c418SJiri Pirko comp->data_size);
281410ed13cSYotam Gigi }
282410ed13cSYotam Gigi
2836a3f707cSSaeed Mahameed mlxfw_dbg(mlxfw_dev, "Component verify\n");
2845853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0);
285410ed13cSYotam Gigi err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
286410ed13cSYotam Gigi comp->index);
287f7fe7aa8SSaeed Mahameed if (err) {
2885042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
2895042e8b9SSaeed Mahameed "FSM component verify failed", err);
290410ed13cSYotam Gigi goto err_out;
291f7fe7aa8SSaeed Mahameed }
292410ed13cSYotam Gigi
29344f18db5SJiri Pirko err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
29444f18db5SJiri Pirko MLXFW_FSM_STATE_LOCKED, extack);
295410ed13cSYotam Gigi if (err)
296410ed13cSYotam Gigi goto err_out;
297410ed13cSYotam Gigi return 0;
298410ed13cSYotam Gigi
299410ed13cSYotam Gigi err_out:
300410ed13cSYotam Gigi mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
301410ed13cSYotam Gigi return err;
302410ed13cSYotam Gigi }
303410ed13cSYotam Gigi
mlxfw_flash_components(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_file * mfa2_file,bool reactivate_supp,struct netlink_ext_ack * extack)304410ed13cSYotam Gigi static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
30544f18db5SJiri Pirko struct mlxfw_mfa2_file *mfa2_file,
306958dfd0dSEran Ben Elisha bool reactivate_supp,
30744f18db5SJiri Pirko struct netlink_ext_ack *extack)
308410ed13cSYotam Gigi {
309410ed13cSYotam Gigi u32 component_count;
310410ed13cSYotam Gigi int err;
311410ed13cSYotam Gigi int i;
312410ed13cSYotam Gigi
313410ed13cSYotam Gigi err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
314410ed13cSYotam Gigi mlxfw_dev->psid_size,
315410ed13cSYotam Gigi &component_count);
316410ed13cSYotam Gigi if (err) {
3175042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
3185042e8b9SSaeed Mahameed "Could not find device PSID in MFA2 file", err);
319410ed13cSYotam Gigi return err;
320410ed13cSYotam Gigi }
321410ed13cSYotam Gigi
322410ed13cSYotam Gigi for (i = 0; i < component_count; i++) {
323410ed13cSYotam Gigi struct mlxfw_mfa2_component *comp;
324410ed13cSYotam Gigi
325410ed13cSYotam Gigi comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
326410ed13cSYotam Gigi mlxfw_dev->psid_size, i);
327f7fe7aa8SSaeed Mahameed if (IS_ERR(comp)) {
328f7fe7aa8SSaeed Mahameed err = PTR_ERR(comp);
3295042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
3305042e8b9SSaeed Mahameed "Failed to get MFA2 component", err);
331f7fe7aa8SSaeed Mahameed return err;
332f7fe7aa8SSaeed Mahameed }
333410ed13cSYotam Gigi
3346a3f707cSSaeed Mahameed mlxfw_info(mlxfw_dev, "Flashing component type %d\n",
3356a3f707cSSaeed Mahameed comp->index);
336958dfd0dSEran Ben Elisha err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp,
337958dfd0dSEran Ben Elisha reactivate_supp, extack);
338410ed13cSYotam Gigi mlxfw_mfa2_file_component_put(comp);
339410ed13cSYotam Gigi if (err)
340410ed13cSYotam Gigi return err;
341410ed13cSYotam Gigi }
342410ed13cSYotam Gigi return 0;
343410ed13cSYotam Gigi }
344410ed13cSYotam Gigi
mlxfw_firmware_flash(struct mlxfw_dev * mlxfw_dev,const struct firmware * firmware,struct netlink_ext_ack * extack)345410ed13cSYotam Gigi int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
34644f18db5SJiri Pirko const struct firmware *firmware,
34744f18db5SJiri Pirko struct netlink_ext_ack *extack)
348410ed13cSYotam Gigi {
349410ed13cSYotam Gigi struct mlxfw_mfa2_file *mfa2_file;
350958dfd0dSEran Ben Elisha bool reactivate_supp = true;
351410ed13cSYotam Gigi u32 fwhandle;
352410ed13cSYotam Gigi int err;
353410ed13cSYotam Gigi
354410ed13cSYotam Gigi if (!mlxfw_mfa2_check(firmware)) {
3555042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
3565042e8b9SSaeed Mahameed "Firmware file is not MFA2", -EINVAL);
357410ed13cSYotam Gigi return -EINVAL;
358410ed13cSYotam Gigi }
359410ed13cSYotam Gigi
360410ed13cSYotam Gigi mfa2_file = mlxfw_mfa2_file_init(firmware);
361f7fe7aa8SSaeed Mahameed if (IS_ERR(mfa2_file)) {
362f7fe7aa8SSaeed Mahameed err = PTR_ERR(mfa2_file);
3635042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
3645042e8b9SSaeed Mahameed "Failed to initialize MFA2 firmware file", err);
365f7fe7aa8SSaeed Mahameed return err;
366f7fe7aa8SSaeed Mahameed }
367410ed13cSYotam Gigi
3686a3f707cSSaeed Mahameed mlxfw_info(mlxfw_dev, "Initialize firmware flash process\n");
3695853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",
3705853c418SJiri Pirko NULL, 0, 0);
371410ed13cSYotam Gigi err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
372410ed13cSYotam Gigi if (err) {
3735042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
3745042e8b9SSaeed Mahameed "Could not lock the firmware FSM", err);
375410ed13cSYotam Gigi goto err_fsm_lock;
376410ed13cSYotam Gigi }
377410ed13cSYotam Gigi
378410ed13cSYotam Gigi err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
37944f18db5SJiri Pirko MLXFW_FSM_STATE_LOCKED, extack);
380410ed13cSYotam Gigi if (err)
381410ed13cSYotam Gigi goto err_state_wait_idle_to_locked;
382410ed13cSYotam Gigi
383958dfd0dSEran Ben Elisha err = mlxfw_fsm_reactivate(mlxfw_dev, extack, &reactivate_supp);
384958dfd0dSEran Ben Elisha if (err)
385958dfd0dSEran Ben Elisha goto err_fsm_reactivate;
386958dfd0dSEran Ben Elisha
387958dfd0dSEran Ben Elisha err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
388958dfd0dSEran Ben Elisha MLXFW_FSM_STATE_LOCKED, extack);
389958dfd0dSEran Ben Elisha if (err)
390958dfd0dSEran Ben Elisha goto err_state_wait_reactivate_to_locked;
391958dfd0dSEran Ben Elisha
392958dfd0dSEran Ben Elisha err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file,
393958dfd0dSEran Ben Elisha reactivate_supp, extack);
394410ed13cSYotam Gigi if (err)
395410ed13cSYotam Gigi goto err_flash_components;
396410ed13cSYotam Gigi
3976a3f707cSSaeed Mahameed mlxfw_dbg(mlxfw_dev, "Activate image\n");
3985853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);
399410ed13cSYotam Gigi err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
400410ed13cSYotam Gigi if (err) {
4015042e8b9SSaeed Mahameed MLXFW_ERR_MSG(mlxfw_dev, extack,
4025042e8b9SSaeed Mahameed "Could not activate the downloaded image", err);
403410ed13cSYotam Gigi goto err_fsm_activate;
404410ed13cSYotam Gigi }
405410ed13cSYotam Gigi
40644f18db5SJiri Pirko err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
40744f18db5SJiri Pirko MLXFW_FSM_STATE_LOCKED, extack);
408410ed13cSYotam Gigi if (err)
409410ed13cSYotam Gigi goto err_state_wait_activate_to_locked;
410410ed13cSYotam Gigi
4116a3f707cSSaeed Mahameed mlxfw_dbg(mlxfw_dev, "Handle release\n");
412410ed13cSYotam Gigi mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
413410ed13cSYotam Gigi
4146a3f707cSSaeed Mahameed mlxfw_info(mlxfw_dev, "Firmware flash done\n");
4155853c418SJiri Pirko mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);
416410ed13cSYotam Gigi mlxfw_mfa2_file_fini(mfa2_file);
417410ed13cSYotam Gigi return 0;
418410ed13cSYotam Gigi
419410ed13cSYotam Gigi err_state_wait_activate_to_locked:
420410ed13cSYotam Gigi err_fsm_activate:
421410ed13cSYotam Gigi err_flash_components:
422958dfd0dSEran Ben Elisha err_state_wait_reactivate_to_locked:
423958dfd0dSEran Ben Elisha err_fsm_reactivate:
424410ed13cSYotam Gigi err_state_wait_idle_to_locked:
425410ed13cSYotam Gigi mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
426410ed13cSYotam Gigi err_fsm_lock:
427410ed13cSYotam Gigi mlxfw_mfa2_file_fini(mfa2_file);
428410ed13cSYotam Gigi return err;
429410ed13cSYotam Gigi }
430410ed13cSYotam Gigi EXPORT_SYMBOL(mlxfw_firmware_flash);
431410ed13cSYotam Gigi
432410ed13cSYotam Gigi MODULE_LICENSE("Dual BSD/GPL");
433410ed13cSYotam Gigi MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
434410ed13cSYotam Gigi MODULE_DESCRIPTION("Mellanox firmware flash lib");
435