| From c5b08694f165c3d11a8085323357eae7182d3140 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 14 Feb 2020 18:44:52 +0300 |
| Subject: net: atlantic: check rpc result and wait for rpc address |
| |
| From: Igor Russkikh <irusskikh@marvell.com> |
| |
| [ Upstream commit e7b5f97e6574dc4918e375d5f8d24ec31653cd6d ] |
| |
| Artificial HW reliability tests revealed a possible hangup in |
| the driver. Normally, when device disappears from bus, all |
| register reads returns 0xFFFFFFFF. |
| |
| At remote procedure invocation towards FW there is a logic |
| where result is compared with -1 in a loop. |
| That caused an infinite loop if hardware due to some issues |
| disappears from bus. |
| |
| Add extra result checks to prevent this. |
| |
| Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com> |
| Signed-off-by: Igor Russkikh <irusskikh@marvell.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 19 +++++++++++++++++-- |
| 1 file changed, 17 insertions(+), 2 deletions(-) |
| |
| 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 f547baa6c9549..354705f9bc493 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 |
| @@ -22,6 +22,7 @@ |
| #define HW_ATL_MIF_ADDR 0x0208U |
| #define HW_ATL_MIF_VAL 0x020CU |
| |
| +#define HW_ATL_MPI_RPC_ADDR 0x0334U |
| #define HW_ATL_RPC_CONTROL_ADR 0x0338U |
| #define HW_ATL_RPC_STATE_ADR 0x033CU |
| |
| @@ -53,15 +54,14 @@ enum mcp_area { |
| }; |
| |
| static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); |
| - |
| static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, |
| enum hal_atl_utils_fw_state_e state); |
| - |
| static u32 hw_atl_utils_get_mpi_mbox_tid(struct aq_hw_s *self); |
| static u32 hw_atl_utils_mpi_get_state(struct aq_hw_s *self); |
| static u32 hw_atl_utils_mif_cmd_get(struct aq_hw_s *self); |
| static u32 hw_atl_utils_mif_addr_get(struct aq_hw_s *self); |
| static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self); |
| +static u32 aq_fw1x_rpc_get(struct aq_hw_s *self); |
| |
| int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) |
| { |
| @@ -476,6 +476,10 @@ static int hw_atl_utils_init_ucp(struct aq_hw_s *self, |
| self, self->mbox_addr, |
| self->mbox_addr != 0U, |
| 1000U, 10000U); |
| + err = readx_poll_timeout_atomic(aq_fw1x_rpc_get, self, |
| + self->rpc_addr, |
| + self->rpc_addr != 0U, |
| + 1000U, 100000U); |
| |
| return err; |
| } |
| @@ -531,6 +535,12 @@ int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, |
| self, fw.val, |
| sw.tid == fw.tid, |
| 1000U, 100000U); |
| + if (err < 0) |
| + goto err_exit; |
| + |
| + err = aq_hw_err_from_flags(self); |
| + if (err < 0) |
| + goto err_exit; |
| |
| if (fw.len == 0xFFFFU) { |
| err = hw_atl_utils_fw_rpc_call(self, sw.len); |
| @@ -1025,6 +1035,11 @@ static u32 hw_atl_utils_rpc_state_get(struct aq_hw_s *self) |
| return aq_hw_read_reg(self, HW_ATL_RPC_STATE_ADR); |
| } |
| |
| +static u32 aq_fw1x_rpc_get(struct aq_hw_s *self) |
| +{ |
| + return aq_hw_read_reg(self, HW_ATL_MPI_RPC_ADDR); |
| +} |
| + |
| const struct aq_fw_ops aq_fw_1x_ops = { |
| .init = hw_atl_utils_mpi_create, |
| .deinit = hw_atl_fw1x_deinit, |
| -- |
| 2.20.1 |
| |