From: Yana Esina <yana.es...@aquantia.com>

This patch fixes the upload function, which worked incorrectly with
some chips.

Signed-off-by: Yana Esina <yana.es...@aquantia.com>
Signed-off-by: Nikita Danilov <nikita.dani...@aquantia.com>
Tested-by: Nikita Danilov <nikita.dani...@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russk...@aquantia.com>
---
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c |  7 ++++
 .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h |  3 ++
 .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 13 +++++++
 .../aquantia/atlantic/hw_atl/hw_atl_utils.c        | 44 ++++++++++++++--------
 .../aquantia/atlantic/hw_atl/hw_atl_utils.h        |  6 +++
 .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c   |  7 +++-
 6 files changed, 64 insertions(+), 16 deletions(-)

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 10ba035..d0a6ea7 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
@@ -1460,3 +1460,10 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s 
*aq_hw,
        aq_hw_write_reg(aq_hw, HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp),
                        glb_cpu_scratch_scp);
 }
+
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr)
+{
+       aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR,
+                           HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK,
+                           HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT, up_force_intr);
+}
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 dfb426f..7056c73 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
@@ -698,4 +698,7 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, 
u32 reg_wr_strobe);
 /* set pci register reset disable */
 void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 
pci_reg_res_dis);
 
+/* set uP Force Interrupt */
+void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr);
+
 #endif /* HW_ATL_LLH_H */
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 e0cf701..716674a 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
@@ -2387,4 +2387,17 @@
 #define HW_ATL_GLB_CPU_SCRATCH_SCP_ADR(scratch_scp) \
        (0x00000300u + (scratch_scp) * 0x4)
 
+/* register address for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR 0x00000404
+/* bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSK 0x00000002
+/* inverted bitmask for bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_MSKN 0xFFFFFFFD
+/* lower bit position of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_SHIFT 1
+/* width of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_WIDTH 1
+/* default value of bitfield uP Force Interrupt */
+#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
+
 #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 c965e65..b0aaf6f 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
@@ -325,17 +325,31 @@ static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s 
*self, u32 a, u32 *p,
                err = -ETIME;
                goto err_exit;
        }
+       if (IS_CHIP_FEATURE(REVISION_B1)) {
+               u32 offset = 0;
+
+               for (; offset < cnt; ++offset) {
+                       aq_hw_write_reg(self, 0x328, p[offset]);
+                       aq_hw_write_reg(self, 0x32C,
+                                       (0x80000000 | (0xFFFF & (offset * 4))));
+                       hw_atl_mcp_up_force_intr_set(self, 1);
+                       /* 1000 times by 10us = 10ms */
+                       AQ_HW_WAIT_FOR((aq_hw_read_reg(self,
+                                                      0x32C) & 0xF0000000) !=
+                                      0x80000000,
+                                      10, 1000);
+               }
+       } else {
+               u32 offset = 0;
 
-       aq_hw_write_reg(self, 0x00000208U, a);
-
-       for (++cnt; --cnt;) {
-               u32 i = 0U;
+               aq_hw_write_reg(self, 0x208, a);
 
-               aq_hw_write_reg(self, 0x0000020CU, *(p++));
-               aq_hw_write_reg(self, 0x00000200U, 0xC000U);
+               for (; offset < cnt; ++offset) {
+                       aq_hw_write_reg(self, 0x20C, p[offset]);
+                       aq_hw_write_reg(self, 0x200, 0xC000);
 
-               for (i = 1024U;
-                       (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
+                       AQ_HW_WAIT_FOR((aq_hw_read_reg(self, 0x200U) &
+                                       0x100) == 0, 10, 1000);
                }
        }
 
@@ -399,7 +413,7 @@ struct aq_hw_atl_utils_fw_rpc_tid_s {
 
 #define hw_atl_utils_fw_rpc_init(_H_) hw_atl_utils_fw_rpc_wait(_H_, NULL)
 
-static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int 
rpc_size)
+int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size)
 {
        int err = 0;
        struct aq_hw_atl_utils_fw_rpc_tid_s sw;
@@ -411,7 +425,7 @@ static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, 
unsigned int rpc_size)
        err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
                                            (u32 *)(void *)&self->rpc,
                                            (rpc_size + sizeof(u32) -
-                                           sizeof(u8)) / sizeof(u32));
+                                            sizeof(u8)) / sizeof(u32));
        if (err < 0)
                goto err_exit;
 
@@ -423,8 +437,8 @@ static int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, 
unsigned int rpc_size)
        return err;
 }
 
-static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
-                                   struct hw_aq_atl_utils_fw_rpc **rpc)
+int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
+                            struct hw_aq_atl_utils_fw_rpc **rpc)
 {
        int err = 0;
        struct aq_hw_atl_utils_fw_rpc_tid_s sw;
@@ -457,10 +471,10 @@ static int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self,
                        hw_atl_utils_fw_downld_dwords(self,
                                                      self->rpc_addr,
                                                      (u32 *)(void *)
-                                                     &self->rpc,
+                                                      &self->rpc,
                                                      (fw.len + sizeof(u32) -
-                                                     sizeof(u8)) /
-                                                     sizeof(u32));
+                                                      sizeof(u8)) /
+                                                      sizeof(u32));
                        if (err < 0)
                                goto err_exit;
                }
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 b875590..aedb911 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
@@ -316,9 +316,15 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 
*fw_version);
 int hw_atl_utils_update_stats(struct aq_hw_s *self);
 
 struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self);
+
 int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
                                  u32 *p, u32 cnt);
 
+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_aq_atl_utils_fw_rpc **rpc);
+
 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_atl/hw_atl_utils_fw2x.c 
b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
index e379437..3a5ec22 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -21,6 +21,7 @@
 
 #define HW_ATL_FW2X_MPI_EFUSE_ADDR     0x364
 #define HW_ATL_FW2X_MPI_MBOX_ADDR      0x360
+#define HW_ATL_FW2X_MPI_RPC_ADDR        0x334
 
 #define HW_ATL_FW2X_MPI_CONTROL_ADDR   0x368
 #define HW_ATL_FW2X_MPI_CONTROL2_ADDR  0x36C
@@ -38,8 +39,12 @@ static int aq_fw2x_init(struct aq_hw_s *self)
 
        /* check 10 times by 1ms */
        AQ_HW_WAIT_FOR(0U != (self->mbox_addr =
-                       aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
+                      aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR)),
                       1000U, 10U);
+       AQ_HW_WAIT_FOR(0U != (self->rpc_addr =
+                      aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR)),
+                      1000U, 100U);
+
        return err;
 }
 
-- 
2.7.4

Reply via email to