123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /*
- * 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) {
- fsm_state_err = min_t(enum mlxfw_fsm_state_err,
- fsm_state_err, MLXFW_FSM_STATE_ERR_MAX);
- 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");
|