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

