GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / net / ethernet / mellanox / mlxfw / mlxfw_mfa2.c
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
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
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
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
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
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
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 *
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
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
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
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 *
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 *
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 *
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
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
617 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
618 {
619         kfree(mfa2_file);
620 }