The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mlxfw/mlxfw_mfa2.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2017-2019 Mellanox Technologies.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of Mellanox nor the names of contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  * $FreeBSD$
   32  */
   33 
   34 #define pr_fmt(fmt) "mlxfw_mfa2: " fmt
   35 
   36 #include <linux/kernel.h>
   37 #include <linux/module.h>
   38 #include <linux/printk.h>
   39 #include <contrib/xz-embedded/linux/include/linux/xz.h>
   40 
   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 
  108 static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!";
  109 static const int mlxfw_mfa2_fingerprint_len =
  110                         sizeof(mlxfw_mfa2_fingerprint) - 1;
  111 
  112 static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#";
  113 static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1;
  114 
  115 bool mlxfw_mfa2_check(const struct firmware *fw)
  116 {
  117         if (fw->datasize < sizeof(mlxfw_mfa2_fingerprint))
  118                 return false;
  119 
  120         return memcmp(fw->data, mlxfw_mfa2_fingerprint,
  121                       mlxfw_mfa2_fingerprint_len) == 0;
  122 }
  123 
  124 static bool
  125 mlxfw_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 
  141 static bool
  142 mlxfw_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 
  214 static bool
  215 mlxfw_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 %#jx and size %d\n",
  249                  (uintmax_t)((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 
  255 static 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 
  290 struct 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 u8 *first_tlv_ptr;
  298         const u8 *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 = (const u8 *) 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 = (const u8 *) 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 = (const u8 *) 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;
  354 err_out:
  355         kfree(mfa2_file);
  356         return ERR_PTR(-EINVAL);
  357 }
  358 
  359 static const struct mlxfw_mfa2_tlv_multi *
  360 mlxfw_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 
  398 int 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 
  420 static 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 
  455 static 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);
  495 out:
  496         xz_dec_end(xz_dec);
  497         return err;
  498 }
  499 
  500 static const struct mlxfw_mfa2_tlv_component_descriptor *
  501 mlxfw_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 
  527 struct mlxfw_mfa2_comp_data {
  528         struct mlxfw_mfa2_component comp;
  529         u8 buff[0];
  530 };
  531 
  532 static const struct mlxfw_mfa2_tlv_component_descriptor *
  533 mlxfw_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 
  560 struct mlxfw_mfa2_component *
  561 mlxfw_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;
  603 err_out:
  604         kfree(comp_data);
  605         return ERR_PTR(err);
  606 }
  607 
  608 void 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 
  616 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
  617 {
  618         kfree(mfa2_file);
  619 }

Cache object: f329daea9d8360a0a753ecc0f022d387


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.