]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
net: atlantic: check rpc result and wait for rpc address
authorIgor Russkikh <irusskikh@marvell.com>
Fri, 14 Feb 2020 15:44:52 +0000 (18:44 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 17 Feb 2020 03:03:39 +0000 (19:03 -0800)
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>
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c

index f547baa6c95499e5f16313ea47b2c04f18f105ca..354705f9bc493afcbe9c63f28cc36f779eea4be5 100644 (file)
@@ -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,