Add the mlxfw module for Mellanox firmware flash process

The mlxfw module is in charge of common logic needed to flash Mellanox
devices firmware, which consists of:
 - Parse the Mellanox Firmware Archive version 2 (MFA2) format, which is
   the format used to store the Mellanox firmware. The MFA2 format file can
   hold firmware for many different silicon variants, differentiated by a
   unique ID called PSID. In addition, the MFA2 file data section is
   compressed using xz compression to save both file-system space and
   memory at extraction time.
 - Implement the firmware flash state machine logic, which is a common
   logic for Mellanox products needed to flash the firmware to the device.

As the module is shared between different Mellanox products, it defines a
set of callbacks to be implemented by the specific driver for hardware
interaction.

Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Yotam Gigi
2017-05-23 21:56:23 +02:00
committed by David S. Miller
parent ff5f58f53c
commit 410ed13cae
14 changed files with 1537 additions and 0 deletions

View File

@@ -8330,6 +8330,14 @@ W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxsw/
MELLANOX FIRMWARE FLASH LIBRARY (mlxfw)
M: Yotam Gigi <yotamg@mellanox.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlxfw/
MELLANOX MLXCPLD I2C AND MUX DRIVER
M: Vadim Pasternak <vadimp@mellanox.com>
M: Michael Shych <michaelsh@mellanox.com>

View File

@@ -19,5 +19,6 @@ if NET_VENDOR_MELLANOX
source "drivers/net/ethernet/mellanox/mlx4/Kconfig"
source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig"
source "drivers/net/ethernet/mellanox/mlxsw/Kconfig"
source "drivers/net/ethernet/mellanox/mlxfw/Kconfig"
endif # NET_VENDOR_MELLANOX

View File

@@ -5,3 +5,4 @@
obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_MLX5_CORE) += mlx5/core/
obj-$(CONFIG_MLXSW_CORE) += mlxsw/
obj-$(CONFIG_MLXFW) += mlxfw/

View File

@@ -0,0 +1,6 @@
#
# Mellanox firmware flash library configuration
#
config MLXFW
tristate "mlxfw" if COMPILE_TEST

View File

@@ -0,0 +1,2 @@
obj-$(CONFIG_MLXFW) += mlxfw.o
mlxfw-objs := mlxfw_fsm.o mlxfw_mfa2_tlv_multi.o mlxfw_mfa2.o

View File

@@ -0,0 +1,102 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw.h
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#ifndef _MLXFW_H
#define _MLXFW_H
#include <linux/firmware.h>
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 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

View File

@@ -0,0 +1,273 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw.c
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#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");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2.h
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#ifndef _MLXFW_MFA2_H
#define _MLXFW_MFA2_H
#include <linux/firmware.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

View File

@@ -0,0 +1,60 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_file.h
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#ifndef _MLXFW_MFA2_FILE_H
#define _MLXFW_MFA2_FILE_H
#include <linux/firmware.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 void *ptr)
{
const void *valid_to = mfa2_file->fw->data + mfa2_file->fw->size;
const void *valid_from = mfa2_file->fw->data;
return ptr > valid_from && ptr < valid_to;
}
#endif

View File

@@ -0,0 +1,103 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#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

View File

@@ -0,0 +1,98 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv.h
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#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 void *ptr)
{
if (!mlxfw_mfa2_valid_ptr(mfa2_file, ptr) ||
!mlxfw_mfa2_valid_ptr(mfa2_file, ptr + sizeof(struct mlxfw_mfa2_tlv)))
return NULL;
return 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)
{
void *tlv_top;
tlv_top = (void *) tlv + be16_to_cpu(tlv->len) - 1;
if (!mlxfw_mfa2_valid_ptr(mfa2_file, 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

View File

@@ -0,0 +1,126 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.c
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#define pr_fmt(fmt) "MFA2: " fmt
#include "mlxfw_mfa2_tlv_multi.h"
#include <uapi/linux/netlink.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, (void *) 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;
void *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 = (void *) 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;
}

View File

@@ -0,0 +1,71 @@
/*
* drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_tlv_multi.h
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
*
* 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 names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#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