diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index d775b23025c16..9c3debae425fc 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only -/* - * aQuantia Corporation Network Driver - * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved +/* Atlantic Network Driver + * + * Copyright (C) 2014-2019 aQuantia Corporation + * Copyright (C) 2019-2020 Marvell International Ltd. */ /* File hw_atl_llh.c: Definitions of bitfield and register access functions for @@ -1724,6 +1725,16 @@ u32 hw_atl_sem_mdio_get(struct aq_hw_s *self) return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_MDIO); } +u32 hw_atl_sem_reset1_get(struct aq_hw_s *self) +{ + return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RESET1); +} + +u32 hw_atl_sem_reset2_get(struct aq_hw_s *self) +{ + return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RESET2); +} + u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp) { return aq_hw_read_reg(aq_hw, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 61a6f70c51cd9..f0954711df24c 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* - * aQuantia Corporation Network Driver - * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved +/* Atlantic Network Driver + * + * Copyright (C) 2014-2019 aQuantia Corporation + * Copyright (C) 2019-2020 Marvell International Ltd. */ /* File hw_atl_llh.h: Declarations of bitfield and register access functions for @@ -838,6 +839,9 @@ u32 hw_atl_sem_ram_get(struct aq_hw_s *self); /* get global microprocessor mdio semaphore */ u32 hw_atl_sem_mdio_get(struct aq_hw_s *self); +u32 hw_atl_sem_reset1_get(struct aq_hw_s *self); +u32 hw_atl_sem_reset2_get(struct aq_hw_s *self); + /* get global microprocessor scratch pad register */ u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 7430ff0251341..ee11cb88325e5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* - * aQuantia Corporation Network Driver - * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved +/* Atlantic Network Driver + * + * Copyright (C) 2014-2019 aQuantia Corporation + * Copyright (C) 2019-2020 Marvell International Ltd. */ /* File hw_atl_llh_internal.h: Preprocessor definitions @@ -2837,7 +2838,11 @@ /* Default value of bitfield MDIO Address [F:0] */ #define HW_ATL_MDIO_ADDRESS_DEFAULT 0x0 +#define HW_ATL_MIF_RESET_TIMEOUT_ADR 0x00000348 + #define HW_ATL_FW_SM_MDIO 0x0U #define HW_ATL_FW_SM_RAM 0x2U +#define HW_ATL_FW_SM_RESET1 0x3U +#define HW_ATL_FW_SM_RESET2 0x4U #endif /* HW_ATL_LLH_INTERNAL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index bf4c41cc312b0..cacab3352cb8e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -46,6 +46,7 @@ #define HW_ATL_FW_VER_1X 0x01050006U #define HW_ATL_FW_VER_2X 0x02000000U #define HW_ATL_FW_VER_3X 0x03000000U +#define HW_ATL_FW_VER_4X 0x04000000U #define FORCE_FLASHLESS 0 @@ -72,14 +73,13 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) self->fw_ver_actual = hw_atl_utils_get_fw_version(self); - if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, - self->fw_ver_actual) == 0) { + if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, self->fw_ver_actual)) { *fw_ops = &aq_fw_1x_ops; - } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, - self->fw_ver_actual) == 0) { + } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_2X, self->fw_ver_actual)) { *fw_ops = &aq_fw_2x_ops; - } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, - self->fw_ver_actual) == 0) { + } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_3X, self->fw_ver_actual)) { + *fw_ops = &aq_fw_2x_ops; + } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, self->fw_ver_actual)) { *fw_ops = &aq_fw_2x_ops; } else { aq_pr_err("Bad FW version detected: %x\n", @@ -239,6 +239,7 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) int hw_atl_utils_soft_reset(struct aq_hw_s *self) { + int ver = hw_atl_utils_get_fw_version(self); u32 boot_exit_code = 0; u32 val; int k; @@ -259,14 +260,12 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self) self->rbl_enabled = (boot_exit_code != 0); - /* FW 1.x may bootup in an invalid POWER state (WOL feature). - * We should work around this by forcing its state back to DEINIT - */ - if (!hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, - aq_hw_read_reg(self, - HW_ATL_MPI_FW_VERSION))) { + if (hw_atl_utils_ver_match(HW_ATL_FW_VER_1X, ver)) { int err = 0; + /* FW 1.x may bootup in an invalid POWER state (WOL feature). + * We should work around this by forcing its state back to DEINIT + */ hw_atl_utils_mpi_set_state(self, MPI_DEINIT); err = readx_poll_timeout_atomic(hw_atl_utils_mpi_get_state, self, val, @@ -275,6 +274,27 @@ int hw_atl_utils_soft_reset(struct aq_hw_s *self) 10, 10000U); if (err) return err; + } else if (hw_atl_utils_ver_match(HW_ATL_FW_VER_4X, ver)) { + u64 sem_timeout = aq_hw_read_reg(self, HW_ATL_MIF_RESET_TIMEOUT_ADR); + + /* Acquire 2 semaphores before issuing reset for FW 4.x */ + if (sem_timeout > 3000) + sem_timeout = 3000; + sem_timeout = sem_timeout * 1000; + + if (sem_timeout != 0) { + int err; + + err = readx_poll_timeout_atomic(hw_atl_sem_reset1_get, self, val, + val == 1U, 1U, sem_timeout); + if (err) + aq_pr_err("reset sema1 timeout"); + + err = readx_poll_timeout_atomic(hw_atl_sem_reset2_get, self, val, + val == 1U, 1U, sem_timeout); + if (err) + aq_pr_err("reset sema2 timeout"); + } } if (self->rbl_enabled) @@ -434,20 +454,20 @@ int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p, p, cnt, MCP_AREA_SETTINGS); } -int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) +bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) { const u32 dw_major_mask = 0xff000000U; const u32 dw_minor_mask = 0x00ffffffU; - int err = 0; + bool ver_match; - err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0; - if (err < 0) + ver_match = (dw_major_mask & (ver_expected ^ ver_actual)) ? false : true; + if (!ver_match) goto err_exit; - err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ? - -EOPNOTSUPP : 0; + ver_match = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ? + false : true; err_exit: - return err; + return ver_match; } static int hw_atl_utils_init_ucp(struct aq_hw_s *self, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 0b4b54fc1de03..f5901f8e39077 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -635,7 +635,7 @@ int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size); int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, struct hw_atl_utils_fw_rpc **rpc); -int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); +bool hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); extern const struct aq_fw_ops aq_fw_1x_ops; extern const struct aq_fw_ops aq_fw_2x_ops; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c index f3766780e9756..0fe6257d9c08d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils.c @@ -36,8 +36,7 @@ int hw_atl2_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) self->fw_ver_actual = hw_atl2_utils_get_fw_version(self); - if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X, - self->fw_ver_actual) == 0) { + if (hw_atl_utils_ver_match(HW_ATL2_FW_VER_1X, self->fw_ver_actual)) { *fw_ops = &aq_a2_fw_ops; } else { aq_pr_err("Bad FW version detected: %x, but continue\n",