Initial version of Mellanox in-kernel firmware upgrade support.
Submitted by: slavash@ MFC after: 3 days Sponsored by: Mellanox Technologies
This commit is contained in:
parent
8d593abae4
commit
3b2324c3a8
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 29, 2018
|
||||
.Dd May 8, 2019
|
||||
.Dt MLX5EN 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -37,6 +37,9 @@ kernel configuration file:
|
||||
.Bd -ragged -offset indent
|
||||
.Cd "options COMPAT_LINUXKPI"
|
||||
.Cd "options RATELIMIT"
|
||||
.Cd "device xz"
|
||||
.Cd "device mlxfw"
|
||||
.Cd "device firmware"
|
||||
.Cd "device mlx5"
|
||||
.Cd "device mlx5en"
|
||||
.Ed
|
||||
|
@ -2376,6 +2376,12 @@ dev/mii/ukphy_subr.c optional miibus | mii
|
||||
dev/mii/vscphy.c optional miibus | vscphy
|
||||
dev/mii/xmphy.c optional miibus | xmphy
|
||||
dev/mk48txx/mk48txx.c optional mk48txx
|
||||
dev/mlxfw/mlxfw_fsm.c optional mlxfw \
|
||||
compile-with "${MLXFW_C}"
|
||||
dev/mlxfw/mlxfw_mfa2.c optional mlxfw \
|
||||
compile-with "${MLXFW_C}"
|
||||
dev/mlxfw/mlxfw_mfa2_tlv_multi.c optional mlxfw \
|
||||
compile-with "${MLXFW_C}"
|
||||
dev/mlx/mlx.c optional mlx
|
||||
dev/mlx/mlx_disk.c optional mlx
|
||||
dev/mlx/mlx_pci.c optional mlx pci
|
||||
|
@ -229,6 +229,12 @@ OFEDCFLAGS= ${CFLAGS:N-I*} -DCONFIG_INFINIBAND_USER_MEM \
|
||||
OFED_C_NOIMP= ${CC} -c -o ${.TARGET} ${OFEDCFLAGS} ${WERROR} ${PROF}
|
||||
OFED_C= ${OFED_C_NOIMP} ${.IMPSRC}
|
||||
|
||||
# mlxfw C flags.
|
||||
MLXFW_C= ${OFED_C_NOIMP} \
|
||||
-I${SRCTOP}/sys/contrib/xz-embedded/freebsd \
|
||||
-I${SRCTOP}/sys/contrib/xz-embedded/linux/lib/xz \
|
||||
${.IMPSRC}
|
||||
|
||||
GEN_CFILES= $S/$M/$M/genassym.c ${MFILES:T:S/.m$/.c/}
|
||||
SYSTEM_CFILES= config.c env.c hints.c vnode_if.c
|
||||
SYSTEM_DEP= Makefile ${SYSTEM_OBJS}
|
||||
|
104
sys/dev/mlxfw/mlxfw.h
Normal file
104
sys/dev/mlxfw/mlxfw.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MLXFW_H
|
||||
#define _MLXFW_H
|
||||
|
||||
#include <sys/firmware.h>
|
||||
|
||||
#define NLA_ALIGNTO 4
|
||||
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
|
||||
|
||||
enum mlxfw_fsm_state {
|
||||
MLXFW_FSM_STATE_IDLE,
|
||||
MLXFW_FSM_STATE_LOCKED,
|
||||
MLXFW_FSM_STATE_INITIALIZE,
|
||||
MLXFW_FSM_STATE_DOWNLOAD,
|
||||
MLXFW_FSM_STATE_VERIFY,
|
||||
MLXFW_FSM_STATE_APPLY,
|
||||
MLXFW_FSM_STATE_ACTIVATE,
|
||||
};
|
||||
|
||||
enum mlxfw_fsm_state_err {
|
||||
MLXFW_FSM_STATE_ERR_OK,
|
||||
MLXFW_FSM_STATE_ERR_ERROR,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE,
|
||||
MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT,
|
||||
MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET,
|
||||
MLXFW_FSM_STATE_ERR_MAX,
|
||||
};
|
||||
|
||||
struct mlxfw_dev;
|
||||
struct firmware;
|
||||
|
||||
struct mlxfw_dev_ops {
|
||||
int (*component_query)(struct mlxfw_dev *mlxfw_dev, u16 component_index,
|
||||
u32 *p_max_size, u8 *p_align_bits,
|
||||
u16 *p_max_write_size);
|
||||
|
||||
int (*fsm_lock)(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle);
|
||||
|
||||
int (*fsm_component_update)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
|
||||
u16 component_index, u32 component_size);
|
||||
|
||||
int (*fsm_block_download)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
|
||||
u8 *data, u16 size, u32 offset);
|
||||
|
||||
int (*fsm_component_verify)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
|
||||
u16 component_index);
|
||||
|
||||
int (*fsm_activate)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle);
|
||||
|
||||
int (*fsm_query_state)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
|
||||
enum mlxfw_fsm_state *fsm_state,
|
||||
enum mlxfw_fsm_state_err *fsm_state_err);
|
||||
|
||||
void (*fsm_cancel)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle);
|
||||
|
||||
void (*fsm_release)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle);
|
||||
};
|
||||
|
||||
struct mlxfw_dev {
|
||||
const struct mlxfw_dev_ops *ops;
|
||||
const char *psid;
|
||||
u16 psid_size;
|
||||
};
|
||||
|
||||
int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
|
||||
const struct firmware *firmware);
|
||||
#endif
|
275
sys/dev/mlxfw/mlxfw_fsm.c
Normal file
275
sys/dev/mlxfw/mlxfw_fsm.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "mlxfw: " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "mlxfw.h"
|
||||
#include "mlxfw_mfa2.h"
|
||||
|
||||
#define MLXFW_FSM_STATE_WAIT_CYCLE_MS 200
|
||||
#define MLXFW_FSM_STATE_WAIT_TIMEOUT_MS 30000
|
||||
#define MLXFW_FSM_STATE_WAIT_ROUNDS \
|
||||
(MLXFW_FSM_STATE_WAIT_TIMEOUT_MS / MLXFW_FSM_STATE_WAIT_CYCLE_MS)
|
||||
#define MLXFW_FSM_MAX_COMPONENT_SIZE (10 * (1 << 20))
|
||||
|
||||
static const char * const mlxfw_fsm_state_err_str[] = {
|
||||
[MLXFW_FSM_STATE_ERR_ERROR] =
|
||||
"general error",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_DIGEST_ERR] =
|
||||
"component hash mismatch",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_NOT_APPLICABLE] =
|
||||
"component not applicable",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_UNKNOWN_KEY] =
|
||||
"unknown key",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_AUTH_FAILED] =
|
||||
"authentication failed",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_UNSIGNED] =
|
||||
"component was not signed",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_KEY_NOT_APPLICABLE] =
|
||||
"key not applicable",
|
||||
[MLXFW_FSM_STATE_ERR_REJECTED_BAD_FORMAT] =
|
||||
"bad format",
|
||||
[MLXFW_FSM_STATE_ERR_BLOCKED_PENDING_RESET] =
|
||||
"pending reset",
|
||||
[MLXFW_FSM_STATE_ERR_MAX] =
|
||||
"unknown error"
|
||||
};
|
||||
|
||||
static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
|
||||
enum mlxfw_fsm_state fsm_state)
|
||||
{
|
||||
enum mlxfw_fsm_state_err fsm_state_err;
|
||||
enum mlxfw_fsm_state curr_fsm_state;
|
||||
int times;
|
||||
int err;
|
||||
|
||||
times = MLXFW_FSM_STATE_WAIT_ROUNDS;
|
||||
retry:
|
||||
err = mlxfw_dev->ops->fsm_query_state(mlxfw_dev, fwhandle,
|
||||
&curr_fsm_state, &fsm_state_err);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {
|
||||
pr_err("Firmware flash failed: %s\n",
|
||||
mlxfw_fsm_state_err_str[fsm_state_err]);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (curr_fsm_state != fsm_state) {
|
||||
if (--times == 0) {
|
||||
pr_err("Timeout reached on FSM state change");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS);
|
||||
goto retry;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MLXFW_ALIGN_DOWN(x, align_bits) ((x) & ~((1 << (align_bits)) - 1))
|
||||
#define MLXFW_ALIGN_UP(x, align_bits) \
|
||||
MLXFW_ALIGN_DOWN((x) + ((1 << (align_bits)) - 1), (align_bits))
|
||||
|
||||
static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
|
||||
u32 fwhandle,
|
||||
struct mlxfw_mfa2_component *comp)
|
||||
{
|
||||
u16 comp_max_write_size;
|
||||
u8 comp_align_bits;
|
||||
u32 comp_max_size;
|
||||
u16 block_size;
|
||||
u8 *block_ptr;
|
||||
u32 offset;
|
||||
int err;
|
||||
|
||||
err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,
|
||||
&comp_max_size, &comp_align_bits,
|
||||
&comp_max_write_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
comp_max_size = min_t(u32, comp_max_size, MLXFW_FSM_MAX_COMPONENT_SIZE);
|
||||
if (comp->data_size > comp_max_size) {
|
||||
pr_err("Component %d is of size %d which is bigger than limit %d\n",
|
||||
comp->index, comp->data_size, comp_max_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
|
||||
comp_align_bits);
|
||||
|
||||
pr_debug("Component update\n");
|
||||
err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,
|
||||
comp->index,
|
||||
comp->data_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
|
||||
MLXFW_FSM_STATE_DOWNLOAD);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
pr_debug("Component download\n");
|
||||
for (offset = 0;
|
||||
offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);
|
||||
offset += comp_max_write_size) {
|
||||
block_ptr = comp->data + offset;
|
||||
block_size = (u16) min_t(u32, comp->data_size - offset,
|
||||
comp_max_write_size);
|
||||
err = mlxfw_dev->ops->fsm_block_download(mlxfw_dev, fwhandle,
|
||||
block_ptr, block_size,
|
||||
offset);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
pr_debug("Component verify\n");
|
||||
err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,
|
||||
comp->index);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
|
||||
if (err)
|
||||
goto err_out;
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
mlxfw_dev->ops->fsm_cancel(mlxfw_dev, fwhandle);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
|
||||
struct mlxfw_mfa2_file *mfa2_file)
|
||||
{
|
||||
u32 component_count;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid,
|
||||
mlxfw_dev->psid_size,
|
||||
&component_count);
|
||||
if (err) {
|
||||
pr_err("Could not find device PSID in MFA2 file\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < component_count; i++) {
|
||||
struct mlxfw_mfa2_component *comp;
|
||||
|
||||
comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid,
|
||||
mlxfw_dev->psid_size, i);
|
||||
if (IS_ERR(comp))
|
||||
return PTR_ERR(comp);
|
||||
|
||||
pr_info("Flashing component type %d\n", comp->index);
|
||||
err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp);
|
||||
mlxfw_mfa2_file_component_put(comp);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,
|
||||
const struct firmware *firmware)
|
||||
{
|
||||
struct mlxfw_mfa2_file *mfa2_file;
|
||||
u32 fwhandle;
|
||||
int err;
|
||||
|
||||
if (!mlxfw_mfa2_check(firmware)) {
|
||||
pr_err("Firmware file is not MFA2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mfa2_file = mlxfw_mfa2_file_init(firmware);
|
||||
if (IS_ERR(mfa2_file))
|
||||
return PTR_ERR(mfa2_file);
|
||||
|
||||
pr_info("Initialize firmware flash process\n");
|
||||
err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);
|
||||
if (err) {
|
||||
pr_err("Could not lock the firmware FSM\n");
|
||||
goto err_fsm_lock;
|
||||
}
|
||||
|
||||
err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle,
|
||||
MLXFW_FSM_STATE_LOCKED);
|
||||
if (err)
|
||||
goto err_state_wait_idle_to_locked;
|
||||
|
||||
err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file);
|
||||
if (err)
|
||||
goto err_flash_components;
|
||||
|
||||
pr_debug("Activate image\n");
|
||||
err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);
|
||||
if (err) {
|
||||
pr_err("Could not activate the downloaded image\n");
|
||||
goto err_fsm_activate;
|
||||
}
|
||||
|
||||
err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED);
|
||||
if (err)
|
||||
goto err_state_wait_activate_to_locked;
|
||||
|
||||
pr_debug("Handle release\n");
|
||||
mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
|
||||
|
||||
pr_info("Firmware flash done.\n");
|
||||
mlxfw_mfa2_file_fini(mfa2_file);
|
||||
return 0;
|
||||
|
||||
err_state_wait_activate_to_locked:
|
||||
err_fsm_activate:
|
||||
err_flash_components:
|
||||
err_state_wait_idle_to_locked:
|
||||
mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);
|
||||
err_fsm_lock:
|
||||
mlxfw_mfa2_file_fini(mfa2_file);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mlxfw_firmware_flash);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_AUTHOR("Yotam Gigi <yotamg@mellanox.com>");
|
||||
MODULE_DESCRIPTION("Mellanox firmware flash lib");
|
||||
MODULE_VERSION(mlxfw, 1);
|
||||
MODULE_DEPEND(mlxfw, linuxkpi, 1, 1, 1);
|
||||
MODULE_DEPEND(mlxfw, xz, 1, 1, 1);
|
619
sys/dev/mlxfw/mlxfw_mfa2.c
Normal file
619
sys/dev/mlxfw/mlxfw_mfa2.c
Normal file
@ -0,0 +1,619 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "mlxfw_mfa2: " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
#include <contrib/xz-embedded/linux/include/linux/xz.h>
|
||||
|
||||
#include "mlxfw_mfa2.h"
|
||||
#include "mlxfw_mfa2_file.h"
|
||||
#include "mlxfw_mfa2_tlv.h"
|
||||
#include "mlxfw_mfa2_format.h"
|
||||
#include "mlxfw_mfa2_tlv_multi.h"
|
||||
|
||||
/* MFA2 FILE
|
||||
* +----------------------------------+
|
||||
* | MFA2 finger print |
|
||||
* +----------------------------------+
|
||||
* | package descriptor multi_tlv |
|
||||
* | +------------------------------+ | +-----------------+
|
||||
* | | package descriptor tlv +-----> |num_devices=n |
|
||||
* | +------------------------------+ | |num_components=m |
|
||||
* +----------------------------------+ |CB offset |
|
||||
* | device descriptor multi_tlv | |... |
|
||||
* | +------------------------------+ | | |
|
||||
* | | PSID tlv | | +-----------------+
|
||||
* | +------------------------------+ |
|
||||
* | | component index tlv | |
|
||||
* | +------------------------------+ |
|
||||
* +----------------------------------+
|
||||
* | component descriptor multi_tlv |
|
||||
* | +------------------------------+ | +-----------------+
|
||||
* | | component descriptor tlv +-----> |Among others: |
|
||||
* | +------------------------------+ | |CB offset=o |
|
||||
* +----------------------------------+ |comp index=i |
|
||||
* | | |... |
|
||||
* | | | |
|
||||
* | | +-----------------+
|
||||
* | COMPONENT BLOCK (CB) |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* +----------------------------------+
|
||||
*
|
||||
* On the top level, an MFA2 file contains:
|
||||
* - Fingerprint
|
||||
* - Several multi_tlvs (TLVs of type MLXFW_MFA2_TLV_MULTI, as defined in
|
||||
* mlxfw_mfa2_format.h)
|
||||
* - Compresses content block
|
||||
*
|
||||
* The first multi_tlv
|
||||
* -------------------
|
||||
* The first multi TLV is treated as package descriptor, and expected to have a
|
||||
* first TLV child of type MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR which contains all
|
||||
* the global information needed to parse the file. Among others, it contains
|
||||
* the number of device descriptors and component descriptor following this
|
||||
* multi TLV.
|
||||
*
|
||||
* The device descriptor multi_tlv
|
||||
* -------------------------------
|
||||
* The multi TLVs following the package descriptor are treated as device
|
||||
* descriptor, and are expected to have the following children:
|
||||
* - PSID TLV child of type MLXFW_MFA2_TLV_PSID containing that device PSID.
|
||||
* - Component index of type MLXFW_MFA2_TLV_COMPONENT_PTR that contains that
|
||||
* device component index.
|
||||
*
|
||||
* The component descriptor multi_tlv
|
||||
* ----------------------------------
|
||||
* The multi TLVs following the device descriptor multi TLVs are treated as
|
||||
* component descriptor, and are expected to have a first child of type
|
||||
* MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR that contains mostly the component index,
|
||||
* needed for the flash process and the offset to the binary within the
|
||||
* component block.
|
||||
*/
|
||||
|
||||
static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!";
|
||||
static const int mlxfw_mfa2_fingerprint_len =
|
||||
sizeof(mlxfw_mfa2_fingerprint) - 1;
|
||||
|
||||
static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#";
|
||||
static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1;
|
||||
|
||||
bool mlxfw_mfa2_check(const struct firmware *fw)
|
||||
{
|
||||
if (fw->datasize < sizeof(mlxfw_mfa2_fingerprint))
|
||||
return false;
|
||||
|
||||
return memcmp(fw->data, mlxfw_mfa2_fingerprint,
|
||||
mlxfw_mfa2_fingerprint_len) == 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u16 idx;
|
||||
|
||||
/* Check that all children are valid */
|
||||
mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
|
||||
if (!tlv) {
|
||||
pr_err("Multi has invalid child");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *dev_tlv,
|
||||
u16 dev_idx)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_component_ptr *cptr;
|
||||
const struct mlxfw_mfa2_tlv_multi *multi;
|
||||
const struct mlxfw_mfa2_tlv_psid *psid;
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u16 cptr_count;
|
||||
u16 cptr_idx;
|
||||
int err;
|
||||
|
||||
pr_debug("Device %d\n", dev_idx);
|
||||
|
||||
multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
|
||||
if (!multi) {
|
||||
pr_err("Device %d is not a valid TLV error\n", dev_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
|
||||
return false;
|
||||
|
||||
/* Validate the device has PSID tlv */
|
||||
tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
|
||||
MLXFW_MFA2_TLV_PSID, 0);
|
||||
if (!tlv) {
|
||||
pr_err("Device %d does not have PSID\n", dev_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
|
||||
if (!psid) {
|
||||
pr_err("Device %d PSID TLV is not valid\n", dev_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
print_hex_dump_debug(" -- Device PSID ", DUMP_PREFIX_NONE, 16, 16,
|
||||
psid->psid, be16_to_cpu(tlv->len), true);
|
||||
|
||||
/* Validate the device has COMPONENT_PTR */
|
||||
err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi,
|
||||
MLXFW_MFA2_TLV_COMPONENT_PTR,
|
||||
&cptr_count);
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
if (cptr_count == 0) {
|
||||
pr_err("Device %d has no components\n", dev_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) {
|
||||
tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
|
||||
MLXFW_MFA2_TLV_COMPONENT_PTR,
|
||||
cptr_idx);
|
||||
if (!tlv)
|
||||
return false;
|
||||
|
||||
cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv);
|
||||
if (!cptr) {
|
||||
pr_err("Device %d COMPONENT_PTR TLV is not valid\n",
|
||||
dev_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
pr_debug(" -- Component index %d\n",
|
||||
be16_to_cpu(cptr->component_index));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *comp_tlv,
|
||||
u16 comp_idx)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_component_descriptor *cdesc;
|
||||
const struct mlxfw_mfa2_tlv_multi *multi;
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
|
||||
pr_debug("Component %d\n", comp_idx);
|
||||
|
||||
multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
|
||||
if (!multi) {
|
||||
pr_err("Component %d is not a valid TLV error\n", comp_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
|
||||
return false;
|
||||
|
||||
/* Check that component have COMPONENT_DESCRIPTOR as first child */
|
||||
tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
|
||||
if (!tlv) {
|
||||
pr_err("Component descriptor %d multi TLV error\n", comp_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv);
|
||||
if (!cdesc) {
|
||||
pr_err("Component %d does not have a valid descriptor\n",
|
||||
comp_idx);
|
||||
return false;
|
||||
}
|
||||
pr_debug(" -- Component type %d\n", be16_to_cpu(cdesc->identifier));
|
||||
pr_debug(" -- Offset %#jx and size %d\n",
|
||||
(uintmax_t)((u64) be32_to_cpu(cdesc->cb_offset_h) << 32)
|
||||
| be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u16 idx;
|
||||
|
||||
pr_debug("Validating file\n");
|
||||
|
||||
/* check that all the devices exist */
|
||||
mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev,
|
||||
mfa2_file->dev_count) {
|
||||
if (!tlv) {
|
||||
pr_err("Device TLV error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check each device */
|
||||
if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* check that all the components exist */
|
||||
mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component,
|
||||
mfa2_file->component_count) {
|
||||
if (!tlv) {
|
||||
pr_err("Device TLV error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check each component */
|
||||
if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_package_descriptor *pd;
|
||||
const struct mlxfw_mfa2_tlv_multi *multi;
|
||||
const struct mlxfw_mfa2_tlv *multi_child;
|
||||
const struct mlxfw_mfa2_tlv *first_tlv;
|
||||
struct mlxfw_mfa2_file *mfa2_file;
|
||||
const u8 *first_tlv_ptr;
|
||||
const u8 *cb_top_ptr;
|
||||
|
||||
mfa2_file = kcalloc(1, sizeof(*mfa2_file), GFP_KERNEL);
|
||||
if (!mfa2_file)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mfa2_file->fw = fw;
|
||||
first_tlv_ptr = (const u8 *) fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len);
|
||||
first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr);
|
||||
if (!first_tlv) {
|
||||
pr_err("Could not parse package descriptor TLV\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv);
|
||||
if (!multi) {
|
||||
pr_err("First TLV is not of valid multi type\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
|
||||
if (!multi_child)
|
||||
goto err_out;
|
||||
|
||||
pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child);
|
||||
if (!pd) {
|
||||
pr_err("Could not parse package descriptor TLV\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv);
|
||||
if (!mfa2_file->first_dev) {
|
||||
pr_err("First device TLV is not valid\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
mfa2_file->dev_count = be16_to_cpu(pd->num_devices);
|
||||
mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file,
|
||||
mfa2_file->first_dev,
|
||||
mfa2_file->dev_count);
|
||||
mfa2_file->component_count = be16_to_cpu(pd->num_components);
|
||||
mfa2_file->cb = (const u8 *) fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset));
|
||||
if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) {
|
||||
pr_err("Component block is out side the file\n");
|
||||
goto err_out;
|
||||
}
|
||||
mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size);
|
||||
cb_top_ptr = (const u8 *) mfa2_file->cb + mfa2_file->cb_archive_size - 1;
|
||||
if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) {
|
||||
pr_err("Component block size is too big\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!mlxfw_mfa2_file_validate(mfa2_file))
|
||||
goto err_out;
|
||||
return mfa2_file;
|
||||
err_out:
|
||||
kfree(mfa2_file);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static const struct mlxfw_mfa2_tlv_multi *
|
||||
mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const char *psid, u16 psid_size)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_psid *tlv_psid;
|
||||
const struct mlxfw_mfa2_tlv_multi *dev_multi;
|
||||
const struct mlxfw_mfa2_tlv *dev_tlv;
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u32 idx;
|
||||
|
||||
/* for each device tlv */
|
||||
mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev,
|
||||
mfa2_file->dev_count) {
|
||||
if (!dev_tlv)
|
||||
return NULL;
|
||||
|
||||
dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
|
||||
if (!dev_multi)
|
||||
return NULL;
|
||||
|
||||
/* find psid child and compare */
|
||||
tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
|
||||
MLXFW_MFA2_TLV_PSID, 0);
|
||||
if (!tlv)
|
||||
return NULL;
|
||||
if (be16_to_cpu(tlv->len) != psid_size)
|
||||
continue;
|
||||
|
||||
tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
|
||||
if (!tlv_psid)
|
||||
return NULL;
|
||||
|
||||
if (memcmp(psid, tlv_psid->psid, psid_size) == 0)
|
||||
return dev_multi;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const char *psid, u32 psid_size,
|
||||
u32 *p_count)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_multi *dev_multi;
|
||||
u16 count;
|
||||
int err;
|
||||
|
||||
dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
|
||||
if (!dev_multi)
|
||||
return -EINVAL;
|
||||
|
||||
err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi,
|
||||
MLXFW_MFA2_TLV_COMPONENT_PTR,
|
||||
&count);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*p_count = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf,
|
||||
bool *finished)
|
||||
{
|
||||
enum xz_ret xz_ret;
|
||||
|
||||
xz_ret = xz_dec_run(xz_dec, xz_buf);
|
||||
|
||||
switch (xz_ret) {
|
||||
case XZ_STREAM_END:
|
||||
*finished = true;
|
||||
return 0;
|
||||
case XZ_OK:
|
||||
*finished = false;
|
||||
return 0;
|
||||
case XZ_MEM_ERROR:
|
||||
pr_err("xz no memory\n");
|
||||
return -ENOMEM;
|
||||
case XZ_DATA_ERROR:
|
||||
pr_err("xz file corrupted\n");
|
||||
return -EINVAL;
|
||||
case XZ_FORMAT_ERROR:
|
||||
pr_err("xz format not found\n");
|
||||
return -EINVAL;
|
||||
case XZ_OPTIONS_ERROR:
|
||||
pr_err("unsupported xz option\n");
|
||||
return -EINVAL;
|
||||
case XZ_MEMLIMIT_ERROR:
|
||||
pr_err("xz dictionary too small\n");
|
||||
return -EINVAL;
|
||||
default:
|
||||
pr_err("xz error %d\n", xz_ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
off_t off, size_t size, u8 *buf)
|
||||
{
|
||||
struct xz_dec *xz_dec;
|
||||
struct xz_buf dec_buf;
|
||||
off_t curr_off = 0;
|
||||
bool finished;
|
||||
int err;
|
||||
|
||||
xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1);
|
||||
if (!xz_dec)
|
||||
return -EINVAL;
|
||||
|
||||
dec_buf.in_size = mfa2_file->cb_archive_size;
|
||||
dec_buf.in = mfa2_file->cb;
|
||||
dec_buf.in_pos = 0;
|
||||
dec_buf.out = buf;
|
||||
|
||||
/* decode up to the offset */
|
||||
do {
|
||||
dec_buf.out_pos = 0;
|
||||
dec_buf.out_size = min_t(size_t, size, off - curr_off);
|
||||
if (dec_buf.out_size == 0)
|
||||
break;
|
||||
|
||||
err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
|
||||
if (err)
|
||||
goto out;
|
||||
if (finished) {
|
||||
pr_err("xz section too short\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
curr_off += dec_buf.out_pos;
|
||||
} while (curr_off != off);
|
||||
|
||||
/* decode the needed section */
|
||||
dec_buf.out_pos = 0;
|
||||
dec_buf.out_size = size;
|
||||
err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
|
||||
out:
|
||||
xz_dec_end(xz_dec);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct mlxfw_mfa2_tlv_component_descriptor *
|
||||
mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
u16 comp_index)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_multi *multi;
|
||||
const struct mlxfw_mfa2_tlv *multi_child;
|
||||
const struct mlxfw_mfa2_tlv *comp_tlv;
|
||||
|
||||
if (comp_index > mfa2_file->component_count)
|
||||
return NULL;
|
||||
|
||||
comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component,
|
||||
comp_index);
|
||||
if (!comp_tlv)
|
||||
return NULL;
|
||||
|
||||
multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
|
||||
if (!multi)
|
||||
return NULL;
|
||||
|
||||
multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
|
||||
if (!multi_child)
|
||||
return NULL;
|
||||
|
||||
return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child);
|
||||
}
|
||||
|
||||
struct mlxfw_mfa2_comp_data {
|
||||
struct mlxfw_mfa2_component comp;
|
||||
u8 buff[0];
|
||||
};
|
||||
|
||||
static const struct mlxfw_mfa2_tlv_component_descriptor *
|
||||
mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const char *psid, int psid_size,
|
||||
int component_index)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_component_ptr *cptr;
|
||||
const struct mlxfw_mfa2_tlv_multi *dev_multi;
|
||||
const struct mlxfw_mfa2_tlv *cptr_tlv;
|
||||
u16 comp_idx;
|
||||
|
||||
dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
|
||||
if (!dev_multi)
|
||||
return NULL;
|
||||
|
||||
cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
|
||||
MLXFW_MFA2_TLV_COMPONENT_PTR,
|
||||
component_index);
|
||||
if (!cptr_tlv)
|
||||
return NULL;
|
||||
|
||||
cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv);
|
||||
if (!cptr)
|
||||
return NULL;
|
||||
|
||||
comp_idx = be16_to_cpu(cptr->component_index);
|
||||
return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx);
|
||||
}
|
||||
|
||||
struct mlxfw_mfa2_component *
|
||||
mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const char *psid, int psid_size,
|
||||
int component_index)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_component_descriptor *comp;
|
||||
struct mlxfw_mfa2_comp_data *comp_data;
|
||||
u32 comp_buf_size;
|
||||
off_t cb_offset;
|
||||
u32 comp_size;
|
||||
int err;
|
||||
|
||||
comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size,
|
||||
component_index);
|
||||
if (!comp)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 |
|
||||
be32_to_cpu(comp->cb_offset_l);
|
||||
comp_size = be32_to_cpu(comp->size);
|
||||
comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
|
||||
|
||||
comp_data = kmalloc(sizeof(*comp_data) + comp_buf_size, GFP_KERNEL);
|
||||
if (!comp_data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
comp_data->comp.data_size = comp_size;
|
||||
comp_data->comp.index = be16_to_cpu(comp->identifier);
|
||||
err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size,
|
||||
comp_data->buff);
|
||||
if (err) {
|
||||
pr_err("Component could not be reached in CB\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic,
|
||||
mlxfw_mfa2_comp_magic_len) != 0) {
|
||||
pr_err("Component has wrong magic\n");
|
||||
err = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
|
||||
return &comp_data->comp;
|
||||
err_out:
|
||||
kfree(comp_data);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp)
|
||||
{
|
||||
const struct mlxfw_mfa2_comp_data *comp_data;
|
||||
|
||||
comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
|
||||
kfree(comp_data);
|
||||
}
|
||||
|
||||
void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
|
||||
{
|
||||
kfree(mfa2_file);
|
||||
}
|
64
sys/dev/mlxfw/mlxfw_mfa2.h
Normal file
64
sys/dev/mlxfw/mlxfw_mfa2.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MLXFW_MFA2_H
|
||||
#define _MLXFW_MFA2_H
|
||||
|
||||
#include "mlxfw.h"
|
||||
|
||||
struct mlxfw_mfa2_component {
|
||||
u16 index;
|
||||
u32 data_size;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
struct mlxfw_mfa2_file;
|
||||
|
||||
bool mlxfw_mfa2_check(const struct firmware *fw);
|
||||
|
||||
struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw);
|
||||
|
||||
int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const char *psid, u32 psid_size,
|
||||
u32 *p_count);
|
||||
|
||||
struct mlxfw_mfa2_component *
|
||||
mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const char *psid, int psid_size,
|
||||
int component_index);
|
||||
|
||||
void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *component);
|
||||
|
||||
void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file);
|
||||
|
||||
#endif
|
59
sys/dev/mlxfw/mlxfw_mfa2_file.h
Normal file
59
sys/dev/mlxfw/mlxfw_mfa2_file.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MLXFW_MFA2_FILE_H
|
||||
#define _MLXFW_MFA2_FILE_H
|
||||
|
||||
#include "mlxfw.h"
|
||||
#include <linux/kernel.h>
|
||||
|
||||
struct mlxfw_mfa2_file {
|
||||
const struct firmware *fw;
|
||||
const struct mlxfw_mfa2_tlv *first_dev;
|
||||
u16 dev_count;
|
||||
const struct mlxfw_mfa2_tlv *first_component;
|
||||
u16 component_count;
|
||||
const void *cb; /* components block */
|
||||
u32 cb_archive_size; /* size of compressed components block */
|
||||
};
|
||||
|
||||
static inline bool mlxfw_mfa2_valid_ptr(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const u8 *ptr)
|
||||
{
|
||||
const u8 *valid_to = (const u8 *) mfa2_file->fw->data + mfa2_file->fw->datasize;
|
||||
const u8 *valid_from = mfa2_file->fw->data;
|
||||
|
||||
return ptr > valid_from && ptr < valid_to;
|
||||
}
|
||||
|
||||
#endif
|
103
sys/dev/mlxfw/mlxfw_mfa2_format.h
Normal file
103
sys/dev/mlxfw/mlxfw_mfa2_format.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MLXFW_MFA2_FORMAT_H
|
||||
#define _MLXFW_MFA2_FORMAT_H
|
||||
|
||||
#include "mlxfw_mfa2_file.h"
|
||||
#include "mlxfw_mfa2_tlv.h"
|
||||
|
||||
enum mlxfw_mfa2_tlv_type {
|
||||
MLXFW_MFA2_TLV_MULTI_PART = 0x01,
|
||||
MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR = 0x02,
|
||||
MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR = 0x04,
|
||||
MLXFW_MFA2_TLV_COMPONENT_PTR = 0x22,
|
||||
MLXFW_MFA2_TLV_PSID = 0x2A,
|
||||
};
|
||||
|
||||
enum mlxfw_mfa2_compression_type {
|
||||
MLXFW_MFA2_COMPRESSION_TYPE_NONE,
|
||||
MLXFW_MFA2_COMPRESSION_TYPE_XZ,
|
||||
};
|
||||
|
||||
struct mlxfw_mfa2_tlv_package_descriptor {
|
||||
__be16 num_components;
|
||||
__be16 num_devices;
|
||||
__be32 cb_offset;
|
||||
__be32 cb_archive_size;
|
||||
__be32 cb_size_h;
|
||||
__be32 cb_size_l;
|
||||
u8 padding[3];
|
||||
u8 cv_compression;
|
||||
__be32 user_data_offset;
|
||||
} __packed;
|
||||
|
||||
MLXFW_MFA2_TLV(package_descriptor, struct mlxfw_mfa2_tlv_package_descriptor,
|
||||
MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR);
|
||||
|
||||
struct mlxfw_mfa2_tlv_multi {
|
||||
__be16 num_extensions;
|
||||
__be16 total_len;
|
||||
} __packed;
|
||||
|
||||
MLXFW_MFA2_TLV(multi, struct mlxfw_mfa2_tlv_multi,
|
||||
MLXFW_MFA2_TLV_MULTI_PART);
|
||||
|
||||
struct mlxfw_mfa2_tlv_psid {
|
||||
u8 psid[0];
|
||||
} __packed;
|
||||
|
||||
MLXFW_MFA2_TLV_VARSIZE(psid, struct mlxfw_mfa2_tlv_psid,
|
||||
MLXFW_MFA2_TLV_PSID);
|
||||
|
||||
struct mlxfw_mfa2_tlv_component_ptr {
|
||||
__be16 storage_id;
|
||||
__be16 component_index;
|
||||
__be32 storage_address;
|
||||
} __packed;
|
||||
|
||||
MLXFW_MFA2_TLV(component_ptr, struct mlxfw_mfa2_tlv_component_ptr,
|
||||
MLXFW_MFA2_TLV_COMPONENT_PTR);
|
||||
|
||||
struct mlxfw_mfa2_tlv_component_descriptor {
|
||||
__be16 pldm_classification;
|
||||
__be16 identifier;
|
||||
__be32 cb_offset_h;
|
||||
__be32 cb_offset_l;
|
||||
__be32 size;
|
||||
} __packed;
|
||||
|
||||
MLXFW_MFA2_TLV(component_descriptor, struct mlxfw_mfa2_tlv_component_descriptor,
|
||||
MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR);
|
||||
|
||||
#endif
|
97
sys/dev/mlxfw/mlxfw_mfa2_tlv.h
Normal file
97
sys/dev/mlxfw/mlxfw_mfa2_tlv.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MLXFW_MFA2_TLV_H
|
||||
#define _MLXFW_MFA2_TLV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "mlxfw_mfa2_file.h"
|
||||
|
||||
struct mlxfw_mfa2_tlv {
|
||||
u8 version;
|
||||
u8 type;
|
||||
__be16 len;
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
static inline const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_get(const struct mlxfw_mfa2_file *mfa2_file, const u8 *ptr)
|
||||
{
|
||||
if (!mlxfw_mfa2_valid_ptr(mfa2_file, ptr) ||
|
||||
!mlxfw_mfa2_valid_ptr(mfa2_file, ptr + sizeof(struct mlxfw_mfa2_tlv)))
|
||||
return NULL;
|
||||
return (const struct mlxfw_mfa2_tlv *) ptr;
|
||||
}
|
||||
|
||||
static inline const void *
|
||||
mlxfw_mfa2_tlv_payload_get(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *tlv, u8 payload_type,
|
||||
size_t payload_size, bool varsize)
|
||||
{
|
||||
const u8 *tlv_top;
|
||||
|
||||
tlv_top = (const u8 *) tlv + be16_to_cpu(tlv->len) - 1;
|
||||
if (!mlxfw_mfa2_valid_ptr(mfa2_file, (const u8 *) tlv) ||
|
||||
!mlxfw_mfa2_valid_ptr(mfa2_file, tlv_top))
|
||||
return NULL;
|
||||
if (tlv->type != payload_type)
|
||||
return NULL;
|
||||
if (varsize && (be16_to_cpu(tlv->len) < payload_size))
|
||||
return NULL;
|
||||
if (!varsize && (be16_to_cpu(tlv->len) != payload_size))
|
||||
return NULL;
|
||||
|
||||
return tlv->data;
|
||||
}
|
||||
|
||||
#define MLXFW_MFA2_TLV(name, payload_type, tlv_type) \
|
||||
static inline const payload_type * \
|
||||
mlxfw_mfa2_tlv_ ## name ## _get(const struct mlxfw_mfa2_file *mfa2_file, \
|
||||
const struct mlxfw_mfa2_tlv *tlv) \
|
||||
{ \
|
||||
return mlxfw_mfa2_tlv_payload_get(mfa2_file, tlv, \
|
||||
tlv_type, sizeof(payload_type), \
|
||||
false); \
|
||||
}
|
||||
|
||||
#define MLXFW_MFA2_TLV_VARSIZE(name, payload_type, tlv_type) \
|
||||
static inline const payload_type * \
|
||||
mlxfw_mfa2_tlv_ ## name ## _get(const struct mlxfw_mfa2_file *mfa2_file, \
|
||||
const struct mlxfw_mfa2_tlv *tlv) \
|
||||
{ \
|
||||
return mlxfw_mfa2_tlv_payload_get(mfa2_file, tlv, \
|
||||
tlv_type, sizeof(payload_type), \
|
||||
true); \
|
||||
}
|
||||
|
||||
#endif
|
124
sys/dev/mlxfw/mlxfw_mfa2_tlv_multi.c
Normal file
124
sys/dev/mlxfw/mlxfw_mfa2_tlv_multi.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "MFA2: " fmt
|
||||
|
||||
#include "mlxfw_mfa2_tlv_multi.h"
|
||||
|
||||
#define MLXFW_MFA2_TLV_TOTAL_SIZE(tlv) \
|
||||
NLA_ALIGN(sizeof(*(tlv)) + be16_to_cpu((tlv)->len))
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_multi_child(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi)
|
||||
{
|
||||
size_t multi_len;
|
||||
|
||||
multi_len = NLA_ALIGN(sizeof(struct mlxfw_mfa2_tlv_multi));
|
||||
return mlxfw_mfa2_tlv_get(mfa2_file, (const u8 *) multi + multi_len);
|
||||
}
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *tlv)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv_multi *multi;
|
||||
u16 tlv_len;
|
||||
const u8 *next;
|
||||
|
||||
tlv_len = MLXFW_MFA2_TLV_TOTAL_SIZE(tlv);
|
||||
|
||||
if (tlv->type == MLXFW_MFA2_TLV_MULTI_PART) {
|
||||
multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, tlv);
|
||||
tlv_len = NLA_ALIGN(tlv_len + be16_to_cpu(multi->total_len));
|
||||
}
|
||||
|
||||
next = (const u8 *) tlv + tlv_len;
|
||||
return mlxfw_mfa2_tlv_get(mfa2_file, next);
|
||||
}
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_advance(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *from_tlv, u16 count)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u16 idx;
|
||||
|
||||
mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, from_tlv, count)
|
||||
if (!tlv)
|
||||
return NULL;
|
||||
return tlv;
|
||||
}
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_multi_child_find(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi,
|
||||
enum mlxfw_mfa2_tlv_type type, u16 index)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u16 skip = 0;
|
||||
u16 idx;
|
||||
|
||||
mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
|
||||
if (!tlv) {
|
||||
pr_err("TLV parsing error\n");
|
||||
return NULL;
|
||||
}
|
||||
if (tlv->type == type)
|
||||
if (skip++ == index)
|
||||
return tlv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mlxfw_mfa2_tlv_multi_child_count(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi,
|
||||
enum mlxfw_mfa2_tlv_type type,
|
||||
u16 *p_count)
|
||||
{
|
||||
const struct mlxfw_mfa2_tlv *tlv;
|
||||
u16 count = 0;
|
||||
u16 idx;
|
||||
|
||||
mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
|
||||
if (!tlv) {
|
||||
pr_err("TLV parsing error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tlv->type == type)
|
||||
count++;
|
||||
}
|
||||
*p_count = count;
|
||||
return 0;
|
||||
}
|
71
sys/dev/mlxfw/mlxfw_mfa2_tlv_multi.h
Normal file
71
sys/dev/mlxfw/mlxfw_mfa2_tlv_multi.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 2017-2019 Mellanox Technologies.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mellanox nor the names of contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _MLXFW_MFA2_TLV_MULTI_H
|
||||
#define _MLXFW_MFA2_TLV_MULTI_H
|
||||
|
||||
#include "mlxfw_mfa2_tlv.h"
|
||||
#include "mlxfw_mfa2_format.h"
|
||||
#include "mlxfw_mfa2_file.h"
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_multi_child(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi);
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_next(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *tlv);
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_advance(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv *from_tlv, u16 count);
|
||||
|
||||
const struct mlxfw_mfa2_tlv *
|
||||
mlxfw_mfa2_tlv_multi_child_find(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi,
|
||||
enum mlxfw_mfa2_tlv_type type, u16 index);
|
||||
|
||||
int mlxfw_mfa2_tlv_multi_child_count(const struct mlxfw_mfa2_file *mfa2_file,
|
||||
const struct mlxfw_mfa2_tlv_multi *multi,
|
||||
enum mlxfw_mfa2_tlv_type type,
|
||||
u16 *p_count);
|
||||
|
||||
#define mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, from_tlv, count) \
|
||||
for (idx = 0, tlv = from_tlv; idx < (count); \
|
||||
idx++, tlv = mlxfw_mfa2_tlv_next(mfa2_file, tlv))
|
||||
|
||||
#define mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) \
|
||||
mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, \
|
||||
mlxfw_mfa2_tlv_multi_child(mfa2_file, multi), \
|
||||
be16_to_cpu(multi->num_extensions) + 1)
|
||||
#endif
|
@ -237,6 +237,7 @@ SUBDIR= \
|
||||
mfi \
|
||||
mii \
|
||||
mlx \
|
||||
mlxfw \
|
||||
${_mlx4} \
|
||||
${_mlx4ib} \
|
||||
${_mlx4en} \
|
||||
|
17
sys/modules/mlxfw/Makefile
Normal file
17
sys/modules/mlxfw/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
# $FreeBSD$
|
||||
.PATH: ${SRCTOP}/sys/dev/mlxfw
|
||||
|
||||
KMOD=mlxfw
|
||||
SRCS= \
|
||||
mlxfw_fsm.c \
|
||||
mlxfw_mfa2.c \
|
||||
mlxfw_mfa2_tlv_multi.c \
|
||||
device_if.h bus_if.h vnode_if.h pci_if.h
|
||||
|
||||
CFLAGS+= \
|
||||
-I${SRCTOP}/sys/ofed/include \
|
||||
-I${SRCTOP}/sys/compat/linuxkpi/common/include \
|
||||
-I${SRCTOP}/sys/contrib/xz-embedded/freebsd \
|
||||
-I${SRCTOP}/sys/contrib/xz-embedded/linux/lib/xz
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user