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