Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved */
0003 
0004 #define pr_fmt(fmt) "mlxfw_mfa2: " fmt
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/netlink.h>
0009 #include <linux/vmalloc.h>
0010 #include <linux/xz.h>
0011 #include "mlxfw_mfa2.h"
0012 #include "mlxfw_mfa2_file.h"
0013 #include "mlxfw_mfa2_tlv.h"
0014 #include "mlxfw_mfa2_format.h"
0015 #include "mlxfw_mfa2_tlv_multi.h"
0016 
0017 /*               MFA2 FILE
0018  *  +----------------------------------+
0019  *  |        MFA2 finger print         |
0020  *  +----------------------------------+
0021  *  |   package descriptor multi_tlv   |
0022  *  | +------------------------------+ |     +-----------------+
0023  *  | |    package descriptor tlv    +-----> |num_devices=n    |
0024  *  | +------------------------------+ |     |num_components=m |
0025  *  +----------------------------------+     |CB offset        |
0026  *  |    device descriptor multi_tlv   |     |...              |
0027  *  | +------------------------------+ |     |                 |
0028  *  | |           PSID tlv           | |     +-----------------+
0029  *  | +------------------------------+ |
0030  *  | |     component index tlv      | |
0031  *  | +------------------------------+ |
0032  *  +----------------------------------+
0033  *  |  component descriptor multi_tlv  |
0034  *  | +------------------------------+ |     +-----------------+
0035  *  | |  component descriptor tlv    +-----> |Among others:    |
0036  *  | +------------------------------+ |     |CB offset=o      |
0037  *  +----------------------------------+     |comp index=i     |
0038  *  |                                  |     |...              |
0039  *  |                                  |     |                 |
0040  *  |                                  |     +-----------------+
0041  *  |        COMPONENT BLOCK (CB)      |
0042  *  |                                  |
0043  *  |                                  |
0044  *  |                                  |
0045  *  +----------------------------------+
0046  *
0047  * On the top level, an MFA2 file contains:
0048  *  - Fingerprint
0049  *  - Several multi_tlvs (TLVs of type MLXFW_MFA2_TLV_MULTI, as defined in
0050  *    mlxfw_mfa2_format.h)
0051  *  - Compresses content block
0052  *
0053  * The first multi_tlv
0054  * -------------------
0055  * The first multi TLV is treated as package descriptor, and expected to have a
0056  * first TLV child of type MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR which contains all
0057  * the global information needed to parse the file. Among others, it contains
0058  * the number of device descriptors and component descriptor following this
0059  * multi TLV.
0060  *
0061  * The device descriptor multi_tlv
0062  * -------------------------------
0063  * The multi TLVs following the package descriptor are treated as device
0064  * descriptor, and are expected to have the following children:
0065  *  - PSID TLV child of type MLXFW_MFA2_TLV_PSID containing that device PSID.
0066  *  - Component index of type MLXFW_MFA2_TLV_COMPONENT_PTR that contains that
0067  *    device component index.
0068  *
0069  * The component descriptor multi_tlv
0070  * ----------------------------------
0071  * The multi TLVs following the device descriptor multi TLVs are treated as
0072  * component descriptor, and are expected to have a first child of type
0073  * MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR that contains mostly the component index,
0074  * needed for the flash process and the offset to the binary within the
0075  * component block.
0076  */
0077 
0078 static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!";
0079 static const int mlxfw_mfa2_fingerprint_len =
0080             sizeof(mlxfw_mfa2_fingerprint) - 1;
0081 
0082 static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#";
0083 static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1;
0084 
0085 bool mlxfw_mfa2_check(const struct firmware *fw)
0086 {
0087     if (fw->size < sizeof(mlxfw_mfa2_fingerprint))
0088         return false;
0089 
0090     return memcmp(fw->data, mlxfw_mfa2_fingerprint,
0091               mlxfw_mfa2_fingerprint_len) == 0;
0092 }
0093 
0094 static bool
0095 mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file,
0096                   const struct mlxfw_mfa2_tlv_multi *multi)
0097 {
0098     const struct mlxfw_mfa2_tlv *tlv;
0099     u16 idx;
0100 
0101     /* Check that all children are valid */
0102     mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
0103         if (!tlv) {
0104             pr_err("Multi has invalid child");
0105             return false;
0106         }
0107     }
0108     return true;
0109 }
0110 
0111 static bool
0112 mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file,
0113                  const struct mlxfw_mfa2_tlv *dev_tlv,
0114                  u16 dev_idx)
0115 {
0116     const struct mlxfw_mfa2_tlv_component_ptr *cptr;
0117     const struct mlxfw_mfa2_tlv_multi *multi;
0118     const struct mlxfw_mfa2_tlv_psid *psid;
0119     const struct mlxfw_mfa2_tlv *tlv;
0120     u16 cptr_count;
0121     u16 cptr_idx;
0122     int err;
0123 
0124     pr_debug("Device %d\n", dev_idx);
0125 
0126     multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
0127     if (!multi) {
0128         pr_err("Device %d is not a valid TLV error\n", dev_idx);
0129         return false;
0130     }
0131 
0132     if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
0133         return false;
0134 
0135     /* Validate the device has PSID tlv */
0136     tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
0137                           MLXFW_MFA2_TLV_PSID, 0);
0138     if (!tlv) {
0139         pr_err("Device %d does not have PSID\n", dev_idx);
0140         return false;
0141     }
0142 
0143     psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
0144     if (!psid) {
0145         pr_err("Device %d PSID TLV is not valid\n", dev_idx);
0146         return false;
0147     }
0148 
0149     print_hex_dump_debug("  -- Device PSID ", DUMP_PREFIX_NONE, 16, 16,
0150                  psid->psid, be16_to_cpu(tlv->len), true);
0151 
0152     /* Validate the device has COMPONENT_PTR */
0153     err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi,
0154                            MLXFW_MFA2_TLV_COMPONENT_PTR,
0155                            &cptr_count);
0156     if (err)
0157         return false;
0158 
0159     if (cptr_count == 0) {
0160         pr_err("Device %d has no components\n", dev_idx);
0161         return false;
0162     }
0163 
0164     for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) {
0165         tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
0166                               MLXFW_MFA2_TLV_COMPONENT_PTR,
0167                               cptr_idx);
0168         if (!tlv)
0169             return false;
0170 
0171         cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv);
0172         if (!cptr) {
0173             pr_err("Device %d COMPONENT_PTR TLV is not valid\n",
0174                    dev_idx);
0175             return false;
0176         }
0177 
0178         pr_debug("  -- Component index %d\n",
0179              be16_to_cpu(cptr->component_index));
0180     }
0181     return true;
0182 }
0183 
0184 static bool
0185 mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file,
0186                   const struct mlxfw_mfa2_tlv *comp_tlv,
0187                   u16 comp_idx)
0188 {
0189     const struct mlxfw_mfa2_tlv_component_descriptor *cdesc;
0190     const struct mlxfw_mfa2_tlv_multi *multi;
0191     const struct mlxfw_mfa2_tlv *tlv;
0192 
0193     pr_debug("Component %d\n", comp_idx);
0194 
0195     multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
0196     if (!multi) {
0197         pr_err("Component %d is not a valid TLV error\n", comp_idx);
0198         return false;
0199     }
0200 
0201     if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
0202         return false;
0203 
0204     /* Check that component have COMPONENT_DESCRIPTOR as first child */
0205     tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
0206     if (!tlv) {
0207         pr_err("Component descriptor %d multi TLV error\n", comp_idx);
0208         return false;
0209     }
0210 
0211     cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv);
0212     if (!cdesc) {
0213         pr_err("Component %d does not have a valid descriptor\n",
0214                comp_idx);
0215         return false;
0216     }
0217     pr_debug("  -- Component type %d\n", be16_to_cpu(cdesc->identifier));
0218     pr_debug("  -- Offset 0x%llx and size %d\n",
0219          ((u64) be32_to_cpu(cdesc->cb_offset_h) << 32)
0220          | be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size));
0221 
0222     return true;
0223 }
0224 
0225 static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file)
0226 {
0227     const struct mlxfw_mfa2_tlv *tlv;
0228     u16 idx;
0229 
0230     pr_debug("Validating file\n");
0231 
0232     /* check that all the devices exist */
0233     mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev,
0234                    mfa2_file->dev_count) {
0235         if (!tlv) {
0236             pr_err("Device TLV error\n");
0237             return false;
0238         }
0239 
0240         /* Check each device */
0241         if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx))
0242             return false;
0243     }
0244 
0245     /* check that all the components exist */
0246     mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component,
0247                    mfa2_file->component_count) {
0248         if (!tlv) {
0249             pr_err("Device TLV error\n");
0250             return false;
0251         }
0252 
0253         /* Check each component */
0254         if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx))
0255             return false;
0256     }
0257     return true;
0258 }
0259 
0260 struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw)
0261 {
0262     const struct mlxfw_mfa2_tlv_package_descriptor *pd;
0263     const struct mlxfw_mfa2_tlv_multi *multi;
0264     const struct mlxfw_mfa2_tlv *multi_child;
0265     const struct mlxfw_mfa2_tlv *first_tlv;
0266     struct mlxfw_mfa2_file *mfa2_file;
0267     const void *first_tlv_ptr;
0268     const void *cb_top_ptr;
0269 
0270     mfa2_file = kzalloc(sizeof(*mfa2_file), GFP_KERNEL);
0271     if (!mfa2_file)
0272         return ERR_PTR(-ENOMEM);
0273 
0274     mfa2_file->fw = fw;
0275     first_tlv_ptr = fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len);
0276     first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr);
0277     if (!first_tlv) {
0278         pr_err("Could not parse package descriptor TLV\n");
0279         goto err_out;
0280     }
0281 
0282     multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv);
0283     if (!multi) {
0284         pr_err("First TLV is not of valid multi type\n");
0285         goto err_out;
0286     }
0287 
0288     multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
0289     if (!multi_child)
0290         goto err_out;
0291 
0292     pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child);
0293     if (!pd) {
0294         pr_err("Could not parse package descriptor TLV\n");
0295         goto err_out;
0296     }
0297 
0298     mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv);
0299     if (!mfa2_file->first_dev) {
0300         pr_err("First device TLV is not valid\n");
0301         goto err_out;
0302     }
0303 
0304     mfa2_file->dev_count = be16_to_cpu(pd->num_devices);
0305     mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file,
0306                                 mfa2_file->first_dev,
0307                                 mfa2_file->dev_count);
0308     mfa2_file->component_count = be16_to_cpu(pd->num_components);
0309     mfa2_file->cb = fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset));
0310     if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) {
0311         pr_err("Component block is out side the file\n");
0312         goto err_out;
0313     }
0314     mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size);
0315     cb_top_ptr = mfa2_file->cb + mfa2_file->cb_archive_size - 1;
0316     if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) {
0317         pr_err("Component block size is too big\n");
0318         goto err_out;
0319     }
0320 
0321     if (!mlxfw_mfa2_file_validate(mfa2_file))
0322         goto err_out;
0323     return mfa2_file;
0324 err_out:
0325     kfree(mfa2_file);
0326     return ERR_PTR(-EINVAL);
0327 }
0328 
0329 static const struct mlxfw_mfa2_tlv_multi *
0330 mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file,
0331                const char *psid, u16 psid_size)
0332 {
0333     const struct mlxfw_mfa2_tlv_psid *tlv_psid;
0334     const struct mlxfw_mfa2_tlv_multi *dev_multi;
0335     const struct mlxfw_mfa2_tlv *dev_tlv;
0336     const struct mlxfw_mfa2_tlv *tlv;
0337     u32 idx;
0338 
0339     /* for each device tlv */
0340     mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev,
0341                    mfa2_file->dev_count) {
0342         if (!dev_tlv)
0343             return NULL;
0344 
0345         dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
0346         if (!dev_multi)
0347             return NULL;
0348 
0349         /* find psid child and compare */
0350         tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
0351                               MLXFW_MFA2_TLV_PSID, 0);
0352         if (!tlv)
0353             return NULL;
0354         if (be16_to_cpu(tlv->len) != psid_size)
0355             continue;
0356 
0357         tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
0358         if (!tlv_psid)
0359             return NULL;
0360 
0361         if (memcmp(psid, tlv_psid->psid, psid_size) == 0)
0362             return dev_multi;
0363     }
0364 
0365     return NULL;
0366 }
0367 
0368 int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file,
0369                     const char *psid, u32 psid_size,
0370                     u32 *p_count)
0371 {
0372     const struct mlxfw_mfa2_tlv_multi *dev_multi;
0373     u16 count;
0374     int err;
0375 
0376     dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
0377     if (!dev_multi)
0378         return -EINVAL;
0379 
0380     err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi,
0381                            MLXFW_MFA2_TLV_COMPONENT_PTR,
0382                            &count);
0383     if (err)
0384         return err;
0385 
0386     *p_count = count;
0387     return 0;
0388 }
0389 
0390 static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf,
0391                  bool *finished)
0392 {
0393     enum xz_ret xz_ret;
0394 
0395     xz_ret = xz_dec_run(xz_dec, xz_buf);
0396 
0397     switch (xz_ret) {
0398     case XZ_STREAM_END:
0399         *finished = true;
0400         return 0;
0401     case XZ_OK:
0402         *finished = false;
0403         return 0;
0404     case XZ_MEM_ERROR:
0405         pr_err("xz no memory\n");
0406         return -ENOMEM;
0407     case XZ_DATA_ERROR:
0408         pr_err("xz file corrupted\n");
0409         return -EINVAL;
0410     case XZ_FORMAT_ERROR:
0411         pr_err("xz format not found\n");
0412         return -EINVAL;
0413     case XZ_OPTIONS_ERROR:
0414         pr_err("unsupported xz option\n");
0415         return -EINVAL;
0416     case XZ_MEMLIMIT_ERROR:
0417         pr_err("xz dictionary too small\n");
0418         return -EINVAL;
0419     default:
0420         pr_err("xz error %d\n", xz_ret);
0421         return -EINVAL;
0422     }
0423 }
0424 
0425 static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file,
0426                     off_t off, size_t size, u8 *buf)
0427 {
0428     struct xz_dec *xz_dec;
0429     struct xz_buf dec_buf;
0430     off_t curr_off = 0;
0431     bool finished;
0432     int err;
0433 
0434     xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1);
0435     if (!xz_dec)
0436         return -EINVAL;
0437 
0438     dec_buf.in_size = mfa2_file->cb_archive_size;
0439     dec_buf.in = mfa2_file->cb;
0440     dec_buf.in_pos = 0;
0441     dec_buf.out = buf;
0442 
0443     /* decode up to the offset */
0444     do {
0445         dec_buf.out_pos = 0;
0446         dec_buf.out_size = min_t(size_t, size, off - curr_off);
0447         if (dec_buf.out_size == 0)
0448             break;
0449 
0450         err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
0451         if (err)
0452             goto out;
0453         if (finished) {
0454             pr_err("xz section too short\n");
0455             err = -EINVAL;
0456             goto out;
0457         }
0458         curr_off += dec_buf.out_pos;
0459     } while (curr_off != off);
0460 
0461     /* decode the needed section */
0462     dec_buf.out_pos = 0;
0463     dec_buf.out_size = size;
0464     err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
0465 out:
0466     xz_dec_end(xz_dec);
0467     return err;
0468 }
0469 
0470 static const struct mlxfw_mfa2_tlv_component_descriptor *
0471 mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file,
0472                   u16 comp_index)
0473 {
0474     const struct mlxfw_mfa2_tlv_multi *multi;
0475     const struct mlxfw_mfa2_tlv *multi_child;
0476     const struct mlxfw_mfa2_tlv *comp_tlv;
0477 
0478     if (comp_index > mfa2_file->component_count)
0479         return NULL;
0480 
0481     comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component,
0482                       comp_index);
0483     if (!comp_tlv)
0484         return NULL;
0485 
0486     multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
0487     if (!multi)
0488         return NULL;
0489 
0490     multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
0491     if (!multi_child)
0492         return NULL;
0493 
0494     return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child);
0495 }
0496 
0497 struct mlxfw_mfa2_comp_data {
0498     struct mlxfw_mfa2_component comp;
0499     u8 buff[];
0500 };
0501 
0502 static const struct mlxfw_mfa2_tlv_component_descriptor *
0503 mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file,
0504                    const char *psid, int psid_size,
0505                    int component_index)
0506 {
0507     const struct mlxfw_mfa2_tlv_component_ptr *cptr;
0508     const struct mlxfw_mfa2_tlv_multi *dev_multi;
0509     const struct mlxfw_mfa2_tlv *cptr_tlv;
0510     u16 comp_idx;
0511 
0512     dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
0513     if (!dev_multi)
0514         return NULL;
0515 
0516     cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
0517                            MLXFW_MFA2_TLV_COMPONENT_PTR,
0518                            component_index);
0519     if (!cptr_tlv)
0520         return NULL;
0521 
0522     cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv);
0523     if (!cptr)
0524         return NULL;
0525 
0526     comp_idx = be16_to_cpu(cptr->component_index);
0527     return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx);
0528 }
0529 
0530 struct mlxfw_mfa2_component *
0531 mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
0532                   const char *psid, int psid_size,
0533                   int component_index)
0534 {
0535     const struct mlxfw_mfa2_tlv_component_descriptor *comp;
0536     struct mlxfw_mfa2_comp_data *comp_data;
0537     u32 comp_buf_size;
0538     off_t cb_offset;
0539     u32 comp_size;
0540     int err;
0541 
0542     comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size,
0543                           component_index);
0544     if (!comp)
0545         return ERR_PTR(-EINVAL);
0546 
0547     cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 |
0548             be32_to_cpu(comp->cb_offset_l);
0549     comp_size = be32_to_cpu(comp->size);
0550     comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
0551 
0552     comp_data = vzalloc(sizeof(*comp_data) + comp_buf_size);
0553     if (!comp_data)
0554         return ERR_PTR(-ENOMEM);
0555     comp_data->comp.data_size = comp_size;
0556     comp_data->comp.index = be16_to_cpu(comp->identifier);
0557     err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size,
0558                        comp_data->buff);
0559     if (err) {
0560         pr_err("Component could not be reached in CB\n");
0561         goto err_out;
0562     }
0563 
0564     if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic,
0565            mlxfw_mfa2_comp_magic_len) != 0) {
0566         pr_err("Component has wrong magic\n");
0567         err = -EINVAL;
0568         goto err_out;
0569     }
0570 
0571     comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
0572     return &comp_data->comp;
0573 err_out:
0574     vfree(comp_data);
0575     return ERR_PTR(err);
0576 }
0577 
0578 void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp)
0579 {
0580     const struct mlxfw_mfa2_comp_data *comp_data;
0581 
0582     comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
0583     vfree(comp_data);
0584 }
0585 
0586 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
0587 {
0588     kfree(mfa2_file);
0589 }