From: Dima Ruinskiy <[email protected]>

On i210 and i211, writes to the multicast table array (MTA) sometimes
fail silently, leaving the hardware MTA out of sync with the driver's
`mta_shadow` copy.

After updating the MTA in `e1000_update_mc_addr_list_generic()`, read
the registers back on these devices and compare them with `mta_shadow`.
Rewrite any register that does not match, up to three attempts.

Signed-off-by: Grzegorz Siwik <[email protected]>
Signed-off-by: Dima Ruinskiy <[email protected]>
Signed-off-by: Yashaswini Raghuram Prathivadi Bhayankaram 
<[email protected]>
Signed-off-by: Anatoly Burakov <[email protected]>
---
 .mailmap                                 |  1 +
 drivers/net/intel/e1000/base/e1000_mac.c | 34 ++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/.mailmap b/.mailmap
index 6d9e262cfb..f2e35dd968 100644
--- a/.mailmap
+++ b/.mailmap
@@ -1927,6 +1927,7 @@ Yaron Illouz <[email protected]>
 Yaroslav Brustinov <[email protected]>
 Yash Sharma <[email protected]>
 Yashaswini Kanaujia <[email protected]>
+Yashaswini Raghuram Prathivadi Bhayankaram 
<[email protected]>
 Yasufumi Ogawa <[email protected]> <[email protected]>
 Ye Chen <[email protected]>
 Yehor Malikov <[email protected]>
diff --git a/drivers/net/intel/e1000/base/e1000_mac.c 
b/drivers/net/intel/e1000/base/e1000_mac.c
index 408e8e46e8..f794e24b75 100644
--- a/drivers/net/intel/e1000/base/e1000_mac.c
+++ b/drivers/net/intel/e1000/base/e1000_mac.c
@@ -549,6 +549,38 @@ u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 
*mc_addr)
        return hash_value;
 }
 
+/**
+ *  e1000_i21x_mta_workaround - workaround for MTA write failures
+ *  @hw: pointer to the HW structure
+ *
+ *  On I210/I211 sometimes multicast table array writes silently fail.
+ *  Compare to MTA shadow to see if any registers are incorrectly written.
+ *  If a mismatch is found, try to write again up to three times.
+ **/
+static void e1000_i21x_mta_workaround(struct e1000_hw *hw)
+{
+       int failed_cnt = 3;
+       bool is_failed;
+       int i;
+
+       do {
+               is_failed = false;
+               for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) {
+                       if (E1000_READ_REG_ARRAY(hw, E1000_MTA, i) !=
+                           hw->mac.mta_shadow[i]) {
+                               is_failed = true;
+                               E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i,
+                                                     hw->mac.mta_shadow[i]);
+                               E1000_WRITE_FLUSH(hw);
+                       }
+               }
+               if (is_failed && --failed_cnt <= 0) {
+                       DEBUGOUT("Failed to update MTA register, too many 
retries\n");
+                       break;
+               }
+       } while (is_failed);
+}
+
 /**
  *  e1000_update_mc_addr_list_generic - Update Multicast addresses
  *  @hw: pointer to the HW structure
@@ -584,6 +616,8 @@ void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
        for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
                E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
        E1000_WRITE_FLUSH(hw);
+       if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211)
+               e1000_i21x_mta_workaround(hw);
 }
 
 /**
-- 
2.52.0

Reply via email to