xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #define pr_fmt(fmt) "mlxfw: " fmt
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "mlxfw.h"
11*4882a593Smuzhiyun #include "mlxfw_mfa2.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200
14*4882a593Smuzhiyun #define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000
15*4882a593Smuzhiyun #define MLXFW_FSM_STATE_WAIT_ROUNDS \
16*4882a593Smuzhiyun 	(MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS)
17*4882a593Smuzhiyun #define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20))
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static const int mlxfw_fsm_state_errno[] = {
20*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_ERROR] = -EIO,
21*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] = -EBADMSG,
22*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] = -ENOENT,
23*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] = -ENOKEY,
24*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] = -EACCES,
25*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] = -EKEYREVOKED,
26*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] = -EKEYREJECTED,
27*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] = -ENOEXEC,
28*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] = -EBUSY,
29*4882a593Smuzhiyun 	[MLXFW_FSM_STATE_ERR_MAX] = -EINVAL
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define MLXFW_ERR_PRFX "Firmware flash failed: "
33*4882a593Smuzhiyun #define MLXFW_ERR_MSG(fwdev, extack, msg, err) do { \
34*4882a593Smuzhiyun 	mlxfw_err(fwdev, "%s, err (%d)\n", MLXFW_ERR_PRFX msg, err); \
35*4882a593Smuzhiyun 	NL_SET_ERR_MSG_MOD(extack, MLXFW_ERR_PRFX msg); \
36*4882a593Smuzhiyun } while (0)
37*4882a593Smuzhiyun 
mlxfw_fsm_state_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,enum mlxfw_fsm_state_err err)38*4882a593Smuzhiyun static int mlxfw_fsm_state_err(struct mlxfw_dev *mlxfw_dev,
39*4882a593Smuzhiyun 			       struct netlink_ext_ack *extack,
40*4882a593Smuzhiyun 			       enum mlxfw_fsm_state_err err)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	enum mlxfw_fsm_state_err fsm_state_err;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	fsm_state_err = min_t(enum mlxfw_fsm_state_err, err,
45*4882a593Smuzhiyun 			      MLXFW_FSM_STATE_ERR_MAX);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	switch (fsm_state_err) {
48*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_ERROR:
49*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "general error", err);
50*4882a593Smuzhiyun 		break;
51*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR:
52*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "component hash mismatch", err);
53*4882a593Smuzhiyun 		break;
54*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE:
55*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "component not applicable", err);
56*4882a593Smuzhiyun 		break;
57*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY:
58*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown key", err);
59*4882a593Smuzhiyun 		break;
60*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED:
61*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "authentication failed", err);
62*4882a593Smuzhiyun 		break;
63*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED:
64*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "component was not signed", err);
65*4882a593Smuzhiyun 		break;
66*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE:
67*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "key not applicable", err);
68*4882a593Smuzhiyun 		break;
69*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT:
70*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "bad format", err);
71*4882a593Smuzhiyun 		break;
72*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET:
73*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "pending reset", err);
74*4882a593Smuzhiyun 		break;
75*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_OK:
76*4882a593Smuzhiyun 	case MLXFW_FSM_STATE_ERR_MAX:
77*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "unknown error", err);
78*4882a593Smuzhiyun 		break;
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	return mlxfw_fsm_state_errno[fsm_state_err];
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
mlxfw_fsm_state_wait(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,enum mlxfw_fsm_state fsm_state,struct netlink_ext_ack * extack)84*4882a593Smuzhiyun static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
85*4882a593Smuzhiyun 				enum mlxfw_fsm_state fsm_state,
86*4882a593Smuzhiyun 				struct netlink_ext_ack *extack)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	enum mlxfw_fsm_state_err fsm_state_err;
89*4882a593Smuzhiyun 	enum mlxfw_fsm_state curr_fsm_state;
90*4882a593Smuzhiyun 	int times;
91*4882a593Smuzhiyun 	int err;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	times = MLXFW_FSM_STATE_WAIT_ROUNDS;
94*4882a593Smuzhiyun retry:
95*4882a593Smuzhiyun 	err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
96*4882a593Smuzhiyun 					      &curr_fsm_state, &fsm_state_err);
97*4882a593Smuzhiyun 	if (err) {
98*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM state query failed", err);
99*4882a593Smuzhiyun 		return err;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK)
103*4882a593Smuzhiyun 		return mlxfw_fsm_state_err(mlxfw_dev, extack, fsm_state_err);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (curr_fsm_state != fsm_state) {
106*4882a593Smuzhiyun 		if (--times == 0) {
107*4882a593Smuzhiyun 			MLXFW_ERR_MSG(mlxfw_dev, extack,
108*4882a593Smuzhiyun 				      "Timeout reached on FSM state change", -ETIMEDOUT);
109*4882a593Smuzhiyun 			return -ETIMEDOUT;
110*4882a593Smuzhiyun 		}
111*4882a593Smuzhiyun 		msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
112*4882a593Smuzhiyun 		goto retry;
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 	return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static int
mlxfw_fsm_reactivate_err(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,u8 err)118*4882a593Smuzhiyun mlxfw_fsm_reactivate_err(struct mlxfw_dev *mlxfw_dev,
119*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack, u8 err)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	enum mlxfw_fsm_reactivate_status status;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun #define MXFW_REACT_PRFX "Reactivate FSM: "
124*4882a593Smuzhiyun #define MLXFW_REACT_ERR(msg, err) \
125*4882a593Smuzhiyun 	MLXFW_ERR_MSG(mlxfw_dev, extack, MXFW_REACT_PRFX msg, err)
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	status = min_t(enum mlxfw_fsm_reactivate_status, err,
128*4882a593Smuzhiyun 		       MLXFW_FSM_REACTIVATE_STATUS_MAX);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	switch (status) {
131*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_BUSY:
132*4882a593Smuzhiyun 		MLXFW_REACT_ERR("busy", err);
133*4882a593Smuzhiyun 		break;
134*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_PROHIBITED_FW_VER_ERR:
135*4882a593Smuzhiyun 		MLXFW_REACT_ERR("prohibited fw ver", err);
136*4882a593Smuzhiyun 		break;
137*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_COPY_FAILED:
138*4882a593Smuzhiyun 		MLXFW_REACT_ERR("first page copy failed", err);
139*4882a593Smuzhiyun 		break;
140*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_ERASE_FAILED:
141*4882a593Smuzhiyun 		MLXFW_REACT_ERR("first page erase failed", err);
142*4882a593Smuzhiyun 		break;
143*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_FIRST_PAGE_RESTORE_FAILED:
144*4882a593Smuzhiyun 		MLXFW_REACT_ERR("first page restore failed", err);
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_CANDIDATE_FW_DEACTIVATION_FAILED:
147*4882a593Smuzhiyun 		MLXFW_REACT_ERR("candidate fw deactivation failed", err);
148*4882a593Smuzhiyun 		break;
149*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_ERR_DEVICE_RESET_REQUIRED:
150*4882a593Smuzhiyun 		MLXFW_REACT_ERR("device reset required", err);
151*4882a593Smuzhiyun 		break;
152*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_ERR_FW_PROGRAMMING_NEEDED:
153*4882a593Smuzhiyun 		MLXFW_REACT_ERR("fw programming needed", err);
154*4882a593Smuzhiyun 		break;
155*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED:
156*4882a593Smuzhiyun 		MLXFW_REACT_ERR("fw already activated", err);
157*4882a593Smuzhiyun 		break;
158*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_OK:
159*4882a593Smuzhiyun 	case MLXFW_FSM_REACTIVATE_STATUS_MAX:
160*4882a593Smuzhiyun 		MLXFW_REACT_ERR("unexpected error", err);
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	return -EREMOTEIO;
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun 
mlxfw_fsm_reactivate(struct mlxfw_dev * mlxfw_dev,struct netlink_ext_ack * extack,bool * supported)166*4882a593Smuzhiyun static int mlxfw_fsm_reactivate(struct mlxfw_dev *mlxfw_dev,
167*4882a593Smuzhiyun 				struct netlink_ext_ack *extack,
168*4882a593Smuzhiyun 				bool *supported)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	u8 status;
171*4882a593Smuzhiyun 	int err;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (!mlxfw_dev->ops->fsm_reactivate)
174*4882a593Smuzhiyun 		return 0;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	err = mlxfw_dev->ops->fsm_reactivate(mlxfw_dev, &status);
177*4882a593Smuzhiyun 	if (err == -EOPNOTSUPP) {
178*4882a593Smuzhiyun 		*supported = false;
179*4882a593Smuzhiyun 		return 0;
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (err) {
183*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
184*4882a593Smuzhiyun 			      "Could not reactivate firmware flash", err);
185*4882a593Smuzhiyun 		return err;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (status == MLXFW_FSM_REACTIVATE_STATUS_OK ||
189*4882a593Smuzhiyun 	    status == MLXFW_FSM_REACTIVATE_STATUS_FW_ALREADY_ACTIVATED)
190*4882a593Smuzhiyun 		return 0;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return mlxfw_fsm_reactivate_err(mlxfw_dev, extack, status);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
mlxfw_status_notify(struct mlxfw_dev * mlxfw_dev,const char * msg,const char * comp_name,u32 done_bytes,u32 total_bytes)195*4882a593Smuzhiyun static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev,
196*4882a593Smuzhiyun 				const char *msg, const char *comp_name,
197*4882a593Smuzhiyun 				u32 done_bytes, u32 total_bytes)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	devlink_flash_update_status_notify(mlxfw_dev->devlink, msg, comp_name,
200*4882a593Smuzhiyun 					   done_bytes, total_bytes);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun #define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
204*4882a593Smuzhiyun #define MLXFW_ALIGN_UP(x, align_bits) \
205*4882a593Smuzhiyun 		MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
206*4882a593Smuzhiyun 
mlxfw_flash_component(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_component * comp,bool reactivate_supp,struct netlink_ext_ack * extack)207*4882a593Smuzhiyun static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
208*4882a593Smuzhiyun 				 u32 fwhandle,
209*4882a593Smuzhiyun 				 struct mlxfw_mfa2_component *comp,
210*4882a593Smuzhiyun 				 bool reactivate_supp,
211*4882a593Smuzhiyun 				 struct netlink_ext_ack *extack)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	u16 comp_max_write_size;
214*4882a593Smuzhiyun 	u8 comp_align_bits;
215*4882a593Smuzhiyun 	u32 comp_max_size;
216*4882a593Smuzhiyun 	char comp_name[8];
217*4882a593Smuzhiyun 	u16 block_size;
218*4882a593Smuzhiyun 	u8 *block_ptr;
219*4882a593Smuzhiyun 	u32 offset;
220*4882a593Smuzhiyun 	int err;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	sprintf(comp_name, "%u", comp->index);
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
225*4882a593Smuzhiyun 					      &comp_max_size, &comp_align_bits,
226*4882a593Smuzhiyun 					      &comp_max_write_size);
227*4882a593Smuzhiyun 	if (err) {
228*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack, "FSM component query failed", err);
229*4882a593Smuzhiyun 		return err;
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
233*4882a593Smuzhiyun 	if (comp->data_size > comp_max_size) {
234*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
235*4882a593Smuzhiyun 			      "Component size is bigger than limit", -EINVAL);
236*4882a593Smuzhiyun 		return -EINVAL;
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
240*4882a593Smuzhiyun 					       comp_align_bits);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	mlxfw_dbg(mlxfw_dev, "Component update\n");
243*4882a593Smuzhiyun 	mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0);
244*4882a593Smuzhiyun 	err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
245*4882a593Smuzhiyun 						   comp->index,
246*4882a593Smuzhiyun 						   comp->data_size);
247*4882a593Smuzhiyun 	if (err) {
248*4882a593Smuzhiyun 		if (!reactivate_supp)
249*4882a593Smuzhiyun 			MLXFW_ERR_MSG(mlxfw_dev, extack,
250*4882a593Smuzhiyun 				      "FSM component update failed, FW reactivate is not supported",
251*4882a593Smuzhiyun 				      err);
252*4882a593Smuzhiyun 		else
253*4882a593Smuzhiyun 			MLXFW_ERR_MSG(mlxfw_dev, extack,
254*4882a593Smuzhiyun 				      "FSM component update failed", err);
255*4882a593Smuzhiyun 		return err;
256*4882a593Smuzhiyun 	}
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
259*4882a593Smuzhiyun 				   MLXFW_FSM_STATE_DOWNLOAD, extack);
260*4882a593Smuzhiyun 	if (err)
261*4882a593Smuzhiyun 		goto err_out;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	mlxfw_dbg(mlxfw_dev, "Component download\n");
264*4882a593Smuzhiyun 	mlxfw_status_notify(mlxfw_dev, "Downloading component",
265*4882a593Smuzhiyun 			    comp_name, 0, comp->data_size);
266*4882a593Smuzhiyun 	for (offset = 0;
267*4882a593Smuzhiyun 	     offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
268*4882a593Smuzhiyun 	     offset += comp_max_write_size) {
269*4882a593Smuzhiyun 		block_ptr = comp->data + offset;
270*4882a593Smuzhiyun 		block_size = (u16) min_t(u32, comp->data_size - offset,
271*4882a593Smuzhiyun 					 comp_max_write_size);
272*4882a593Smuzhiyun 		err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
273*4882a593Smuzhiyun 							 block_ptr, block_size,
274*4882a593Smuzhiyun 							 offset);
275*4882a593Smuzhiyun 		if (err) {
276*4882a593Smuzhiyun 			MLXFW_ERR_MSG(mlxfw_dev, extack,
277*4882a593Smuzhiyun 				      "Component download failed", err);
278*4882a593Smuzhiyun 			goto err_out;
279*4882a593Smuzhiyun 		}
280*4882a593Smuzhiyun 		mlxfw_status_notify(mlxfw_dev, "Downloading component",
281*4882a593Smuzhiyun 				    comp_name, offset + block_size,
282*4882a593Smuzhiyun 				    comp->data_size);
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	mlxfw_dbg(mlxfw_dev, "Component verify\n");
286*4882a593Smuzhiyun 	mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0);
287*4882a593Smuzhiyun 	err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
288*4882a593Smuzhiyun 						   comp->index);
289*4882a593Smuzhiyun 	if (err) {
290*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
291*4882a593Smuzhiyun 			      "FSM component verify failed", err);
292*4882a593Smuzhiyun 		goto err_out;
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
296*4882a593Smuzhiyun 				   MLXFW_FSM_STATE_LOCKED, extack);
297*4882a593Smuzhiyun 	if (err)
298*4882a593Smuzhiyun 		goto err_out;
299*4882a593Smuzhiyun 	return 0;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun err_out:
302*4882a593Smuzhiyun 	mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
303*4882a593Smuzhiyun 	return err;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
mlxfw_flash_components(struct mlxfw_dev * mlxfw_dev,u32 fwhandle,struct mlxfw_mfa2_file * mfa2_file,bool reactivate_supp,struct netlink_ext_ack * extack)306*4882a593Smuzhiyun static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
307*4882a593Smuzhiyun 				  struct mlxfw_mfa2_file *mfa2_file,
308*4882a593Smuzhiyun 				  bool reactivate_supp,
309*4882a593Smuzhiyun 				  struct netlink_ext_ack *extack)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	u32 component_count;
312*4882a593Smuzhiyun 	int err;
313*4882a593Smuzhiyun 	int i;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
316*4882a593Smuzhiyun 					      mlxfw_dev->psid_size,
317*4882a593Smuzhiyun 					      &component_count);
318*4882a593Smuzhiyun 	if (err) {
319*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
320*4882a593Smuzhiyun 			      "Could not find device PSID in MFA2 file", err);
321*4882a593Smuzhiyun 		return err;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	for (i = 0; i < component_count; i++) {
325*4882a593Smuzhiyun 		struct mlxfw_mfa2_component *comp;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 		comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
328*4882a593Smuzhiyun 						     mlxfw_dev->psid_size, i);
329*4882a593Smuzhiyun 		if (IS_ERR(comp)) {
330*4882a593Smuzhiyun 			err = PTR_ERR(comp);
331*4882a593Smuzhiyun 			MLXFW_ERR_MSG(mlxfw_dev, extack,
332*4882a593Smuzhiyun 				      "Failed to get MFA2 component", err);
333*4882a593Smuzhiyun 			return err;
334*4882a593Smuzhiyun 		}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 		mlxfw_info(mlxfw_dev, "Flashing component type %d\n",
337*4882a593Smuzhiyun 			   comp->index);
338*4882a593Smuzhiyun 		err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp,
339*4882a593Smuzhiyun 					    reactivate_supp, extack);
340*4882a593Smuzhiyun 		mlxfw_mfa2_file_component_put(comp);
341*4882a593Smuzhiyun 		if (err)
342*4882a593Smuzhiyun 			return err;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 	return 0;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
mlxfw_firmware_flash(struct mlxfw_dev * mlxfw_dev,const struct firmware * firmware,struct netlink_ext_ack * extack)347*4882a593Smuzhiyun int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
348*4882a593Smuzhiyun 			 const struct firmware *firmware,
349*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	struct mlxfw_mfa2_file *mfa2_file;
352*4882a593Smuzhiyun 	bool reactivate_supp = true;
353*4882a593Smuzhiyun 	u32 fwhandle;
354*4882a593Smuzhiyun 	int err;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (!mlxfw_mfa2_check(firmware)) {
357*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
358*4882a593Smuzhiyun 			      "Firmware file is not MFA2", -EINVAL);
359*4882a593Smuzhiyun 		return -EINVAL;
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	mfa2_file = mlxfw_mfa2_file_init(firmware);
363*4882a593Smuzhiyun 	if (IS_ERR(mfa2_file)) {
364*4882a593Smuzhiyun 		err = PTR_ERR(mfa2_file);
365*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
366*4882a593Smuzhiyun 			      "Failed to initialize MFA2 firmware file", err);
367*4882a593Smuzhiyun 		return err;
368*4882a593Smuzhiyun 	}
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	mlxfw_info(mlxfw_dev, "Initialize firmware flash process\n");
371*4882a593Smuzhiyun 	devlink_flash_update_begin_notify(mlxfw_dev->devlink);
372*4882a593Smuzhiyun 	mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process",
373*4882a593Smuzhiyun 			    NULL, 0, 0);
374*4882a593Smuzhiyun 	err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
375*4882a593Smuzhiyun 	if (err) {
376*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
377*4882a593Smuzhiyun 			      "Could not lock the firmware FSM", err);
378*4882a593Smuzhiyun 		goto err_fsm_lock;
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
382*4882a593Smuzhiyun 				   MLXFW_FSM_STATE_LOCKED, extack);
383*4882a593Smuzhiyun 	if (err)
384*4882a593Smuzhiyun 		goto err_state_wait_idle_to_locked;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	err = mlxfw_fsm_reactivate(mlxfw_dev, extack, &reactivate_supp);
387*4882a593Smuzhiyun 	if (err)
388*4882a593Smuzhiyun 		goto err_fsm_reactivate;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
391*4882a593Smuzhiyun 				   MLXFW_FSM_STATE_LOCKED, extack);
392*4882a593Smuzhiyun 	if (err)
393*4882a593Smuzhiyun 		goto err_state_wait_reactivate_to_locked;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file,
396*4882a593Smuzhiyun 				     reactivate_supp, extack);
397*4882a593Smuzhiyun 	if (err)
398*4882a593Smuzhiyun 		goto err_flash_components;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	mlxfw_dbg(mlxfw_dev, "Activate image\n");
401*4882a593Smuzhiyun 	mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);
402*4882a593Smuzhiyun 	err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
403*4882a593Smuzhiyun 	if (err) {
404*4882a593Smuzhiyun 		MLXFW_ERR_MSG(mlxfw_dev, extack,
405*4882a593Smuzhiyun 			      "Could not activate the downloaded image", err);
406*4882a593Smuzhiyun 		goto err_fsm_activate;
407*4882a593Smuzhiyun 	}
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
410*4882a593Smuzhiyun 				   MLXFW_FSM_STATE_LOCKED, extack);
411*4882a593Smuzhiyun 	if (err)
412*4882a593Smuzhiyun 		goto err_state_wait_activate_to_locked;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	mlxfw_dbg(mlxfw_dev, "Handle release\n");
415*4882a593Smuzhiyun 	mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	mlxfw_info(mlxfw_dev, "Firmware flash done\n");
418*4882a593Smuzhiyun 	mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);
419*4882a593Smuzhiyun 	mlxfw_mfa2_file_fini(mfa2_file);
420*4882a593Smuzhiyun 	devlink_flash_update_end_notify(mlxfw_dev->devlink);
421*4882a593Smuzhiyun 	return 0;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun err_state_wait_activate_to_locked:
424*4882a593Smuzhiyun err_fsm_activate:
425*4882a593Smuzhiyun err_flash_components:
426*4882a593Smuzhiyun err_state_wait_reactivate_to_locked:
427*4882a593Smuzhiyun err_fsm_reactivate:
428*4882a593Smuzhiyun err_state_wait_idle_to_locked:
429*4882a593Smuzhiyun 	mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
430*4882a593Smuzhiyun err_fsm_lock:
431*4882a593Smuzhiyun 	mlxfw_mfa2_file_fini(mfa2_file);
432*4882a593Smuzhiyun 	devlink_flash_update_end_notify(mlxfw_dev->devlink);
433*4882a593Smuzhiyun 	return err;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun EXPORT_SYMBOL(mlxfw_firmware_flash);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
438*4882a593Smuzhiyun MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
439*4882a593Smuzhiyun MODULE_DESCRIPTION("Mellanox firmware flash lib");
440