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