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