| From 832bd25ff3c0f57da42f5683ba2f8d5ac2457895 Mon Sep 17 00:00:00 2001 |
| From: Dmitry Bogdanov <dmitry.bogdanov@aquantia.com> |
| Date: Fri, 11 Oct 2019 13:45:23 +0000 |
| Subject: [PATCH] net: aquantia: correctly handle macvlan and multicast |
| coexistence |
| |
| commit 9f051db566da1e8110659ab4ab188af1c2510bb4 upstream. |
| |
| macvlan and multicast handling is now mixed up. |
| The explicit issue is that macvlan interface gets broken (no traffic) |
| after clearing MULTICAST flag on the real interface. |
| |
| We now do separate logic and consider both ALLMULTI and MULTICAST |
| flags on the device. |
| |
| Fixes: 11ba961c9161 ("net: aquantia: Fix IFF_ALLMULTI flag functionality") |
| Signed-off-by: Dmitry Bogdanov <dmitry.bogdanov@aquantia.com> |
| Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c |
| index 4ebf083c51c5..f7fa281a46ca 100644 |
| --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c |
| +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c |
| @@ -174,9 +174,7 @@ static void aq_ndev_set_multicast_settings(struct net_device *ndev) |
| { |
| struct aq_nic_s *aq_nic = netdev_priv(ndev); |
| |
| - aq_nic_set_packet_filter(aq_nic, ndev->flags); |
| - |
| - aq_nic_set_multicast_list(aq_nic, ndev); |
| + (void)aq_nic_set_multicast_list(aq_nic, ndev); |
| } |
| |
| static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, |
| diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c |
| index 1a2b09065293..557e9a7bfd28 100644 |
| --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c |
| +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c |
| @@ -617,9 +617,12 @@ int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags) |
| |
| int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) |
| { |
| - unsigned int packet_filter = self->packet_filter; |
| + const struct aq_hw_ops *hw_ops = self->aq_hw_ops; |
| + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; |
| + unsigned int packet_filter = ndev->flags; |
| struct netdev_hw_addr *ha = NULL; |
| unsigned int i = 0U; |
| + int err = 0; |
| |
| self->mc_list.count = 0; |
| if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { |
| @@ -627,29 +630,26 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) |
| } else { |
| netdev_for_each_uc_addr(ha, ndev) { |
| ether_addr_copy(self->mc_list.ar[i++], ha->addr); |
| - |
| - if (i >= AQ_HW_MULTICAST_ADDRESS_MAX) |
| - break; |
| } |
| } |
| |
| - if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { |
| - packet_filter |= IFF_ALLMULTI; |
| - } else { |
| - netdev_for_each_mc_addr(ha, ndev) { |
| - ether_addr_copy(self->mc_list.ar[i++], ha->addr); |
| - |
| - if (i >= AQ_HW_MULTICAST_ADDRESS_MAX) |
| - break; |
| + cfg->is_mc_list_enabled = !!(packet_filter & IFF_MULTICAST); |
| + if (cfg->is_mc_list_enabled) { |
| + if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { |
| + packet_filter |= IFF_ALLMULTI; |
| + } else { |
| + netdev_for_each_mc_addr(ha, ndev) { |
| + ether_addr_copy(self->mc_list.ar[i++], |
| + ha->addr); |
| + } |
| } |
| } |
| |
| if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) { |
| - packet_filter |= IFF_MULTICAST; |
| self->mc_list.count = i; |
| - self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, |
| - self->mc_list.ar, |
| - self->mc_list.count); |
| + err = hw_ops->hw_multicast_list_set(self->aq_hw, |
| + self->mc_list.ar, |
| + self->mc_list.count); |
| } |
| return aq_nic_set_packet_filter(self, packet_filter); |
| } |
| diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c |
| index 23e113fa2986..84914297e326 100644 |
| --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c |
| +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c |
| @@ -788,14 +788,15 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, |
| cfg->is_vlan_force_promisc); |
| |
| hw_atl_rpfl2multicast_flr_en_set(self, |
| - IS_FILTER_ENABLED(IFF_ALLMULTI), 0); |
| + IS_FILTER_ENABLED(IFF_ALLMULTI) && |
| + IS_FILTER_ENABLED(IFF_MULTICAST), 0); |
| |
| hw_atl_rpfl2_accept_all_mc_packets_set(self, |
| - IS_FILTER_ENABLED(IFF_ALLMULTI)); |
| + IS_FILTER_ENABLED(IFF_ALLMULTI) && |
| + IS_FILTER_ENABLED(IFF_MULTICAST)); |
| |
| hw_atl_rpfl2broadcast_en_set(self, IS_FILTER_ENABLED(IFF_BROADCAST)); |
| |
| - cfg->is_mc_list_enabled = IS_FILTER_ENABLED(IFF_MULTICAST); |
| |
| for (i = HW_ATL_B0_MAC_MIN; i < HW_ATL_B0_MAC_MAX; ++i) |
| hw_atl_rpfl2_uc_flr_en_set(self, |
| -- |
| 2.7.4 |
| |