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 } 620