aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/sfc/ef10.c
diff options
context:
space:
mode:
authorDaniel Pieczko <dpieczko@solarflare.com>2015-07-21 10:10:44 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-22 01:21:32 -0400
commitab8b1f7cf83a3016dcdeae874a469e2c8894fcd9 (patch)
tree3338b11c5138f79b5e275ad3524714b87e42409d /drivers/net/ethernet/sfc/ef10.c
parent822b96f87f1b47ac0c73417284879ef610500173 (diff)
sfc: support cascaded multicast filters
If the workaround to support cascaded multicast filters ("workaround_26807") is enabled, the broadcast filter and individual multicast filters are not inserted when in promiscuous or allmulti mode. There is a race while inserting and removing filters when entering and leaving promiscuous mode. When changing promiscuous state with cascaded multicast filters, the old multicast filters are removed before inserting the new filters to avoid duplicating packets; this can lead to dropped packets until all filters have been inserted. The efx_nic:mc_promisc flag is added to record the presence of a multicast promiscuous filter; this gives a simple way to tell if the promiscuous state is changing. Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/sfc/ef10.c')
-rw-r--r--drivers/net/ethernet/sfc/ef10.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 1704f71c7250..0a7cf432adf3 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -3792,26 +3792,42 @@ static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc)
3792static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) 3792static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc)
3793{ 3793{
3794 struct efx_ef10_filter_table *table = efx->filter_state; 3794 struct efx_ef10_filter_table *table = efx->filter_state;
3795 struct efx_ef10_nic_data *nic_data = efx->nic_data;
3795 struct net_device *net_dev = efx->net_dev; 3796 struct net_device *net_dev = efx->net_dev;
3796 struct netdev_hw_addr *mc; 3797 struct netdev_hw_addr *mc;
3797 unsigned int i; 3798 unsigned int i, addr_count;
3798 3799
3799 if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ 3800 if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI))
3800 >= EFX_EF10_FILTER_DEV_MC_MAX) {
3801 table->dev_mc_count = 1;
3802 eth_broadcast_addr(table->dev_mc_list[0].addr);
3803 *promisc = true; 3801 *promisc = true;
3802
3803 if (nic_data->workaround_26807) {
3804 if (*promisc) {
3805 table->dev_mc_count = 0;
3806 return;
3807 }
3808 addr_count = netdev_mc_count(net_dev);
3804 } else { 3809 } else {
3805 table->dev_mc_count = 1 + netdev_mc_count(net_dev); 3810 /* Allow room for broadcast and promiscuous */
3806 eth_broadcast_addr(table->dev_mc_list[0].addr); 3811 addr_count = netdev_mc_count(net_dev) + 2;
3807 i = 1; 3812 }
3808 netdev_for_each_mc_addr(mc, net_dev) { 3813
3809 ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); 3814 if (addr_count >= EFX_EF10_FILTER_DEV_MC_MAX) {
3810 i++; 3815 if (nic_data->workaround_26807) {
3816 table->dev_mc_count = 0;
3817 } else {
3818 table->dev_mc_count = 1;
3819 eth_broadcast_addr(table->dev_mc_list[0].addr);
3811 } 3820 }
3821 *promisc = true;
3822 return;
3823 }
3812 3824
3813 if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) 3825 table->dev_mc_count = 1 + netdev_mc_count(net_dev);
3814 *promisc = true; 3826 eth_broadcast_addr(table->dev_mc_list[0].addr);
3827 i = 1;
3828 netdev_for_each_mc_addr(mc, net_dev) {
3829 ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
3830 i++;
3815 } 3831 }
3816} 3832}
3817 3833
@@ -3846,7 +3862,11 @@ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
3846 * filter for multicast 3862 * filter for multicast
3847 */ 3863 */
3848 while (i--) { 3864 while (i--) {
3849 if (multicast && i == 1) 3865 struct efx_ef10_nic_data *nic_data =
3866 efx->nic_data;
3867
3868 if (multicast && i == 1 &&
3869 !nic_data->workaround_26807)
3850 break; 3870 break;
3851 3871
3852 efx_ef10_filter_remove_safe( 3872 efx_ef10_filter_remove_safe(
@@ -3974,6 +3994,7 @@ reset_nic:
3974static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) 3994static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
3975{ 3995{
3976 struct efx_ef10_filter_table *table = efx->filter_state; 3996 struct efx_ef10_filter_table *table = efx->filter_state;
3997 struct efx_ef10_nic_data *nic_data = efx->nic_data;
3977 struct net_device *net_dev = efx->net_dev; 3998 struct net_device *net_dev = efx->net_dev;
3978 bool uc_promisc = false, mc_promisc = false; 3999 bool uc_promisc = false, mc_promisc = false;
3979 4000
@@ -3995,9 +4016,16 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
3995 4016
3996 /* Insert/renew filters */ 4017 /* Insert/renew filters */
3997 efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); 4018 efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc);
4019
4020 /* If changing promiscuous state with cascaded multicast filters, remove
4021 * old filters first, so that packets are dropped rather than duplicated
4022 */
4023 if (nic_data->workaround_26807 && efx->mc_promisc != mc_promisc)
4024 efx_ef10_filter_remove_old(efx);
3998 efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); 4025 efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc);
3999 4026
4000 efx_ef10_filter_remove_old(efx); 4027 efx_ef10_filter_remove_old(efx);
4028 efx->mc_promisc = mc_promisc;
4001} 4029}
4002 4030
4003static int efx_ef10_set_mac_address(struct efx_nic *efx) 4031static int efx_ef10_set_mac_address(struct efx_nic *efx)