• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.c
3  * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the names of the copyright holders nor the names of its
15  *    contributors may be used to endorse or promote products derived from
16  *    this software without specific prior written permission.
17  *
18  * Alternatively, this software may be distributed under the terms of the
19  * GNU General Public License ("GPL") version 2 as published by the Free
20  * Software Foundation.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #define pr_fmt(fmt) "mlxfw_mfa2: " fmt
36 
37 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/netlink.h>
40 #include <linux/vmalloc.h>
41 #include <linux/xz.h>
42 #include "mlxfw_mfa2.h"
43 #include "mlxfw_mfa2_file.h"
44 #include "mlxfw_mfa2_tlv.h"
45 #include "mlxfw_mfa2_format.h"
46 #include "mlxfw_mfa2_tlv_multi.h"
47 
48 /*               MFA2 FILE
49  *  +----------------------------------+
50  *  |        MFA2 finger print         |
51  *  +----------------------------------+
52  *  |   package descriptor multi_tlv   |
53  *  | +------------------------------+ |     +-----------------+
54  *  | |    package descriptor tlv    +-----> |num_devices=n    |
55  *  | +------------------------------+ |     |num_components=m |
56  *  +----------------------------------+     |CB offset        |
57  *  |    device descriptor multi_tlv   |     |...              |
58  *  | +------------------------------+ |     |                 |
59  *  | |           PSID tlv           | |     +-----------------+
60  *  | +------------------------------+ |
61  *  | |     component index tlv      | |
62  *  | +------------------------------+ |
63  *  +----------------------------------+
64  *  |  component descriptor multi_tlv  |
65  *  | +------------------------------+ |     +-----------------+
66  *  | |  component descriptor tlv    +-----> |Among others:    |
67  *  | +------------------------------+ |     |CB offset=o      |
68  *  +----------------------------------+     |comp index=i     |
69  *  |                                  |     |...              |
70  *  |                                  |     |                 |
71  *  |                                  |     +-----------------+
72  *  |        COMPONENT BLOCK (CB)      |
73  *  |                                  |
74  *  |                                  |
75  *  |                                  |
76  *  +----------------------------------+
77  *
78  * On the top level, an MFA2 file contains:
79  *  - Fingerprint
80  *  - Several multi_tlvs (TLVs of type MLXFW_MFA2_TLV_MULTI, as defined in
81  *    mlxfw_mfa2_format.h)
82  *  - Compresses content block
83  *
84  * The first multi_tlv
85  * -------------------
86  * The first multi TLV is treated as package descriptor, and expected to have a
87  * first TLV child of type MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR which contains all
88  * the global information needed to parse the file. Among others, it contains
89  * the number of device descriptors and component descriptor following this
90  * multi TLV.
91  *
92  * The device descriptor multi_tlv
93  * -------------------------------
94  * The multi TLVs following the package descriptor are treated as device
95  * descriptor, and are expected to have the following children:
96  *  - PSID TLV child of type MLXFW_MFA2_TLV_PSID containing that device PSID.
97  *  - Component index of type MLXFW_MFA2_TLV_COMPONENT_PTR that contains that
98  *    device component index.
99  *
100  * The component descriptor multi_tlv
101  * ----------------------------------
102  * The multi TLVs following the device descriptor multi TLVs are treated as
103  * component descriptor, and are expected to have a first child of type
104  * MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR that contains mostly the component index,
105  * needed for the flash process and the offset to the binary within the
106  * component block.
107  */
108 
109 static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!";
110 static const int mlxfw_mfa2_fingerprint_len =
111 			sizeof(mlxfw_mfa2_fingerprint) - 1;
112 
113 static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#";
114 static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1;
115 
mlxfw_mfa2_check(const struct firmware * fw)116 bool mlxfw_mfa2_check(const struct firmware *fw)
117 {
118 	if (fw->size < sizeof(mlxfw_mfa2_fingerprint))
119 		return false;
120 
121 	return memcmp(fw->data, mlxfw_mfa2_fingerprint,
122 		      mlxfw_mfa2_fingerprint_len) == 0;
123 }
124 
125 static bool
mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file * mfa2_file,const struct mlxfw_mfa2_tlv_multi * multi)126 mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file,
127 			      const struct mlxfw_mfa2_tlv_multi *multi)
128 {
129 	const struct mlxfw_mfa2_tlv *tlv;
130 	u16 idx;
131 
132 	/* Check that all children are valid */
133 	mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
134 		if (!tlv) {
135 			pr_err("Multi has invalid child");
136 			return false;
137 		}
138 	}
139 	return true;
140 }
141 
142 static bool
mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file * mfa2_file,const struct mlxfw_mfa2_tlv * dev_tlv,u16 dev_idx)143 mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file,
144 			     const struct mlxfw_mfa2_tlv *dev_tlv,
145 			     u16 dev_idx)
146 {
147 	const struct mlxfw_mfa2_tlv_component_ptr *cptr;
148 	const struct mlxfw_mfa2_tlv_multi *multi;
149 	const struct mlxfw_mfa2_tlv_psid *psid;
150 	const struct mlxfw_mfa2_tlv *tlv;
151 	u16 cptr_count;
152 	u16 cptr_idx;
153 	int err;
154 
155 	pr_debug("Device %d\n", dev_idx);
156 
157 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
158 	if (!multi) {
159 		pr_err("Device %d is not a valid TLV error\n", dev_idx);
160 		return false;
161 	}
162 
163 	if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
164 		return false;
165 
166 	/* Validate the device has PSID tlv */
167 	tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
168 					      MLXFW_MFA2_TLV_PSID, 0);
169 	if (!tlv) {
170 		pr_err("Device %d does not have PSID\n", dev_idx);
171 		return false;
172 	}
173 
174 	psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
175 	if (!psid) {
176 		pr_err("Device %d PSID TLV is not valid\n", dev_idx);
177 		return false;
178 	}
179 
180 	print_hex_dump_debug("  -- Device PSID ", DUMP_PREFIX_NONE, 16, 16,
181 			     psid->psid, be16_to_cpu(tlv->len), true);
182 
183 	/* Validate the device has COMPONENT_PTR */
184 	err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi,
185 					       MLXFW_MFA2_TLV_COMPONENT_PTR,
186 					       &cptr_count);
187 	if (err)
188 		return false;
189 
190 	if (cptr_count == 0) {
191 		pr_err("Device %d has no components\n", dev_idx);
192 		return false;
193 	}
194 
195 	for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) {
196 		tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
197 						      MLXFW_MFA2_TLV_COMPONENT_PTR,
198 						      cptr_idx);
199 		if (!tlv)
200 			return false;
201 
202 		cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv);
203 		if (!cptr) {
204 			pr_err("Device %d COMPONENT_PTR TLV is not valid\n",
205 			       dev_idx);
206 			return false;
207 		}
208 
209 		pr_debug("  -- Component index %d\n",
210 			 be16_to_cpu(cptr->component_index));
211 	}
212 	return true;
213 }
214 
215 static bool
mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file * mfa2_file,const struct mlxfw_mfa2_tlv * comp_tlv,u16 comp_idx)216 mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file,
217 			      const struct mlxfw_mfa2_tlv *comp_tlv,
218 			      u16 comp_idx)
219 {
220 	const struct mlxfw_mfa2_tlv_component_descriptor *cdesc;
221 	const struct mlxfw_mfa2_tlv_multi *multi;
222 	const struct mlxfw_mfa2_tlv *tlv;
223 
224 	pr_debug("Component %d\n", comp_idx);
225 
226 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
227 	if (!multi) {
228 		pr_err("Component %d is not a valid TLV error\n", comp_idx);
229 		return false;
230 	}
231 
232 	if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
233 		return false;
234 
235 	/* Check that component have COMPONENT_DESCRIPTOR as first child */
236 	tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
237 	if (!tlv) {
238 		pr_err("Component descriptor %d multi TLV error\n", comp_idx);
239 		return false;
240 	}
241 
242 	cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv);
243 	if (!cdesc) {
244 		pr_err("Component %d does not have a valid descriptor\n",
245 		       comp_idx);
246 		return false;
247 	}
248 	pr_debug("  -- Component type %d\n", be16_to_cpu(cdesc->identifier));
249 	pr_debug("  -- Offset 0x%llx and size %d\n",
250 		 ((u64) be32_to_cpu(cdesc->cb_offset_h) << 32)
251 		 | be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size));
252 
253 	return true;
254 }
255 
mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file * mfa2_file)256 static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file)
257 {
258 	const struct mlxfw_mfa2_tlv *tlv;
259 	u16 idx;
260 
261 	pr_debug("Validating file\n");
262 
263 	/* check that all the devices exist */
264 	mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev,
265 			       mfa2_file->dev_count) {
266 		if (!tlv) {
267 			pr_err("Device TLV error\n");
268 			return false;
269 		}
270 
271 		/* Check each device */
272 		if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx))
273 			return false;
274 	}
275 
276 	/* check that all the components exist */
277 	mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component,
278 			       mfa2_file->component_count) {
279 		if (!tlv) {
280 			pr_err("Device TLV error\n");
281 			return false;
282 		}
283 
284 		/* Check each component */
285 		if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx))
286 			return false;
287 	}
288 	return true;
289 }
290 
mlxfw_mfa2_file_init(const struct firmware * fw)291 struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw)
292 {
293 	const struct mlxfw_mfa2_tlv_package_descriptor *pd;
294 	const struct mlxfw_mfa2_tlv_multi *multi;
295 	const struct mlxfw_mfa2_tlv *multi_child;
296 	const struct mlxfw_mfa2_tlv *first_tlv;
297 	struct mlxfw_mfa2_file *mfa2_file;
298 	const void *first_tlv_ptr;
299 	const void *cb_top_ptr;
300 
301 	mfa2_file = kcalloc(1, sizeof(*mfa2_file), GFP_KERNEL);
302 	if (!mfa2_file)
303 		return ERR_PTR(-ENOMEM);
304 
305 	mfa2_file->fw = fw;
306 	first_tlv_ptr = fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len);
307 	first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr);
308 	if (!first_tlv) {
309 		pr_err("Could not parse package descriptor TLV\n");
310 		goto err_out;
311 	}
312 
313 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv);
314 	if (!multi) {
315 		pr_err("First TLV is not of valid multi type\n");
316 		goto err_out;
317 	}
318 
319 	multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
320 	if (!multi_child)
321 		goto err_out;
322 
323 	pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child);
324 	if (!pd) {
325 		pr_err("Could not parse package descriptor TLV\n");
326 		goto err_out;
327 	}
328 
329 	mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv);
330 	if (!mfa2_file->first_dev) {
331 		pr_err("First device TLV is not valid\n");
332 		goto err_out;
333 	}
334 
335 	mfa2_file->dev_count = be16_to_cpu(pd->num_devices);
336 	mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file,
337 							    mfa2_file->first_dev,
338 							    mfa2_file->dev_count);
339 	mfa2_file->component_count = be16_to_cpu(pd->num_components);
340 	mfa2_file->cb = fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset));
341 	if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) {
342 		pr_err("Component block is out side the file\n");
343 		goto err_out;
344 	}
345 	mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size);
346 	cb_top_ptr = mfa2_file->cb + mfa2_file->cb_archive_size - 1;
347 	if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) {
348 		pr_err("Component block size is too big\n");
349 		goto err_out;
350 	}
351 
352 	if (!mlxfw_mfa2_file_validate(mfa2_file))
353 		goto err_out;
354 	return mfa2_file;
355 err_out:
356 	kfree(mfa2_file);
357 	return ERR_PTR(-EINVAL);
358 }
359 
360 static const struct mlxfw_mfa2_tlv_multi *
mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file * mfa2_file,const char * psid,u16 psid_size)361 mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file,
362 		       const char *psid, u16 psid_size)
363 {
364 	const struct mlxfw_mfa2_tlv_psid *tlv_psid;
365 	const struct mlxfw_mfa2_tlv_multi *dev_multi;
366 	const struct mlxfw_mfa2_tlv *dev_tlv;
367 	const struct mlxfw_mfa2_tlv *tlv;
368 	u32 idx;
369 
370 	/* for each device tlv */
371 	mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev,
372 			       mfa2_file->dev_count) {
373 		if (!dev_tlv)
374 			return NULL;
375 
376 		dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
377 		if (!dev_multi)
378 			return NULL;
379 
380 		/* find psid child and compare */
381 		tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
382 						      MLXFW_MFA2_TLV_PSID, 0);
383 		if (!tlv)
384 			return NULL;
385 		if (be16_to_cpu(tlv->len) != psid_size)
386 			continue;
387 
388 		tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
389 		if (!tlv_psid)
390 			return NULL;
391 
392 		if (memcmp(psid, tlv_psid->psid, psid_size) == 0)
393 			return dev_multi;
394 	}
395 
396 	return NULL;
397 }
398 
mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file * mfa2_file,const char * psid,u32 psid_size,u32 * p_count)399 int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file,
400 				    const char *psid, u32 psid_size,
401 				    u32 *p_count)
402 {
403 	const struct mlxfw_mfa2_tlv_multi *dev_multi;
404 	u16 count;
405 	int err;
406 
407 	dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
408 	if (!dev_multi)
409 		return -EINVAL;
410 
411 	err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi,
412 					       MLXFW_MFA2_TLV_COMPONENT_PTR,
413 					       &count);
414 	if (err)
415 		return err;
416 
417 	*p_count = count;
418 	return 0;
419 }
420 
mlxfw_mfa2_xz_dec_run(struct xz_dec * xz_dec,struct xz_buf * xz_buf,bool * finished)421 static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf,
422 				 bool *finished)
423 {
424 	enum xz_ret xz_ret;
425 
426 	xz_ret = xz_dec_run(xz_dec, xz_buf);
427 
428 	switch (xz_ret) {
429 	case XZ_STREAM_END:
430 		*finished = true;
431 		return 0;
432 	case XZ_OK:
433 		*finished = false;
434 		return 0;
435 	case XZ_MEM_ERROR:
436 		pr_err("xz no memory\n");
437 		return -ENOMEM;
438 	case XZ_DATA_ERROR:
439 		pr_err("xz file corrupted\n");
440 		return -EINVAL;
441 	case XZ_FORMAT_ERROR:
442 		pr_err("xz format not found\n");
443 		return -EINVAL;
444 	case XZ_OPTIONS_ERROR:
445 		pr_err("unsupported xz option\n");
446 		return -EINVAL;
447 	case XZ_MEMLIMIT_ERROR:
448 		pr_err("xz dictionary too small\n");
449 		return -EINVAL;
450 	default:
451 		pr_err("xz error %d\n", xz_ret);
452 		return -EINVAL;
453 	}
454 }
455 
mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file * mfa2_file,off_t off,size_t size,u8 * buf)456 static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file,
457 					off_t off, size_t size, u8 *buf)
458 {
459 	struct xz_dec *xz_dec;
460 	struct xz_buf dec_buf;
461 	off_t curr_off = 0;
462 	bool finished;
463 	int err;
464 
465 	xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1);
466 	if (!xz_dec)
467 		return -EINVAL;
468 
469 	dec_buf.in_size = mfa2_file->cb_archive_size;
470 	dec_buf.in = mfa2_file->cb;
471 	dec_buf.in_pos = 0;
472 	dec_buf.out = buf;
473 
474 	/* decode up to the offset */
475 	do {
476 		dec_buf.out_pos = 0;
477 		dec_buf.out_size = min_t(size_t, size, off - curr_off);
478 		if (dec_buf.out_size == 0)
479 			break;
480 
481 		err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
482 		if (err)
483 			goto out;
484 		if (finished) {
485 			pr_err("xz section too short\n");
486 			err = -EINVAL;
487 			goto out;
488 		}
489 		curr_off += dec_buf.out_pos;
490 	} while (curr_off != off);
491 
492 	/* decode the needed section */
493 	dec_buf.out_pos = 0;
494 	dec_buf.out_size = size;
495 	err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
496 out:
497 	xz_dec_end(xz_dec);
498 	return err;
499 }
500 
501 static const struct mlxfw_mfa2_tlv_component_descriptor *
mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file * mfa2_file,u16 comp_index)502 mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file,
503 				  u16 comp_index)
504 {
505 	const struct mlxfw_mfa2_tlv_multi *multi;
506 	const struct mlxfw_mfa2_tlv *multi_child;
507 	const struct mlxfw_mfa2_tlv *comp_tlv;
508 
509 	if (comp_index > mfa2_file->component_count)
510 		return NULL;
511 
512 	comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component,
513 					  comp_index);
514 	if (!comp_tlv)
515 		return NULL;
516 
517 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
518 	if (!multi)
519 		return NULL;
520 
521 	multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
522 	if (!multi_child)
523 		return NULL;
524 
525 	return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child);
526 }
527 
528 struct mlxfw_mfa2_comp_data {
529 	struct mlxfw_mfa2_component comp;
530 	u8 buff[0];
531 };
532 
533 static const struct mlxfw_mfa2_tlv_component_descriptor *
mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file * mfa2_file,const char * psid,int psid_size,int component_index)534 mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file,
535 			       const char *psid, int psid_size,
536 			       int component_index)
537 {
538 	const struct mlxfw_mfa2_tlv_component_ptr *cptr;
539 	const struct mlxfw_mfa2_tlv_multi *dev_multi;
540 	const struct mlxfw_mfa2_tlv *cptr_tlv;
541 	u16 comp_idx;
542 
543 	dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
544 	if (!dev_multi)
545 		return NULL;
546 
547 	cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
548 						   MLXFW_MFA2_TLV_COMPONENT_PTR,
549 						   component_index);
550 	if (!cptr_tlv)
551 		return NULL;
552 
553 	cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv);
554 	if (!cptr)
555 		return NULL;
556 
557 	comp_idx = be16_to_cpu(cptr->component_index);
558 	return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx);
559 }
560 
561 struct mlxfw_mfa2_component *
mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file * mfa2_file,const char * psid,int psid_size,int component_index)562 mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
563 			      const char *psid, int psid_size,
564 			      int component_index)
565 {
566 	const struct mlxfw_mfa2_tlv_component_descriptor *comp;
567 	struct mlxfw_mfa2_comp_data *comp_data;
568 	u32 comp_buf_size;
569 	off_t cb_offset;
570 	u32 comp_size;
571 	int err;
572 
573 	comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size,
574 					      component_index);
575 	if (!comp)
576 		return ERR_PTR(-EINVAL);
577 
578 	cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 |
579 		    be32_to_cpu(comp->cb_offset_l);
580 	comp_size = be32_to_cpu(comp->size);
581 	comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
582 
583 	comp_data = vzalloc(sizeof(*comp_data) + comp_buf_size);
584 	if (!comp_data)
585 		return ERR_PTR(-ENOMEM);
586 	comp_data->comp.data_size = comp_size;
587 	comp_data->comp.index = be16_to_cpu(comp->identifier);
588 	err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size,
589 					   comp_data->buff);
590 	if (err) {
591 		pr_err("Component could not be reached in CB\n");
592 		goto err_out;
593 	}
594 
595 	if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic,
596 		   mlxfw_mfa2_comp_magic_len) != 0) {
597 		pr_err("Component has wrong magic\n");
598 		err = -EINVAL;
599 		goto err_out;
600 	}
601 
602 	comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
603 	return &comp_data->comp;
604 err_out:
605 	vfree(comp_data);
606 	return ERR_PTR(err);
607 }
608 
mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component * comp)609 void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp)
610 {
611 	const struct mlxfw_mfa2_comp_data *comp_data;
612 
613 	comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
614 	vfree(comp_data);
615 }
616 
mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file * mfa2_file)617 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
618 {
619 	kfree(mfa2_file);
620 }
621