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