aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-11-19 18:08:22 -0500
committerBen Hutchings <bhutchings@solarflare.com>2013-08-22 14:26:02 -0400
commit964e61355e94905e4234839d4b41678998d617b7 (patch)
tree317a5e30a89b07eabaa9376bbbb00d574fce4df2
parentf5253d92567b193c6aa137a08e7bb3b06fafc985 (diff)
sfc: Cleanup Falcon-arch simple MAC filter state
On Falcon we implement MAC filtering requested by the stack using the MAC wrapper's single unicast filter and multicast hash filter. Siena is very similar, though MAC configuration is mediated by the MC. Since MCDI operations may sleep, reconfiguration is deferred from ndo_set_rx_mode to a work item. However, it still updates the private variables describing the filter state synchronously. Contrary to comments, the later use of these variables is not protected using the address lock, resulting in race conditions. Move the state update to a new function efx_farch_filter_sync_rx_mode() and make the Falcon-arch MAC configuration functions call that, so that its use is consistently serialised by the mac_lock. Invert and rename the promiscuous flag to the more accurate unicast_filter, and comment that both this and multicast_hash are not used on EF10. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
-rw-r--r--drivers/net/ethernet/sfc/efx.c34
-rw-r--r--drivers/net/ethernet/sfc/falcon.c6
-rw-r--r--drivers/net/ethernet/sfc/farch.c34
-rw-r--r--drivers/net/ethernet/sfc/mcdi_port.c11
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h8
-rw-r--r--drivers/net/ethernet/sfc/nic.h1
-rw-r--r--drivers/net/ethernet/sfc/siena.c2
7 files changed, 52 insertions, 44 deletions
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index a2daaae266d7..1d4f38895b9f 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -17,7 +17,6 @@
17#include <linux/ip.h> 17#include <linux/ip.h>
18#include <linux/tcp.h> 18#include <linux/tcp.h>
19#include <linux/in.h> 19#include <linux/in.h>
20#include <linux/crc32.h>
21#include <linux/ethtool.h> 20#include <linux/ethtool.h>
22#include <linux/topology.h> 21#include <linux/topology.h>
23#include <linux/gfp.h> 22#include <linux/gfp.h>
@@ -876,10 +875,9 @@ void efx_link_status_changed(struct efx_nic *efx)
876 /* Status message for kernel log */ 875 /* Status message for kernel log */
877 if (link_state->up) 876 if (link_state->up)
878 netif_info(efx, link, efx->net_dev, 877 netif_info(efx, link, efx->net_dev,
879 "link up at %uMbps %s-duplex (MTU %d)%s\n", 878 "link up at %uMbps %s-duplex (MTU %d)\n",
880 link_state->speed, link_state->fd ? "full" : "half", 879 link_state->speed, link_state->fd ? "full" : "half",
881 efx->net_dev->mtu, 880 efx->net_dev->mtu);
882 (efx->promiscuous ? " [PROMISC]" : ""));
883 else 881 else
884 netif_info(efx, link, efx->net_dev, "link down\n"); 882 netif_info(efx, link, efx->net_dev, "link down\n");
885} 883}
@@ -928,10 +926,6 @@ int __efx_reconfigure_port(struct efx_nic *efx)
928 926
929 WARN_ON(!mutex_is_locked(&efx->mac_lock)); 927 WARN_ON(!mutex_is_locked(&efx->mac_lock));
930 928
931 /* Serialise the promiscuous flag with efx_set_rx_mode. */
932 netif_addr_lock_bh(efx->net_dev);
933 netif_addr_unlock_bh(efx->net_dev);
934
935 /* Disable PHY transmit in mac level loopbacks */ 929 /* Disable PHY transmit in mac level loopbacks */
936 phy_mode = efx->phy_mode; 930 phy_mode = efx->phy_mode;
937 if (LOOPBACK_INTERNAL(efx)) 931 if (LOOPBACK_INTERNAL(efx))
@@ -2027,30 +2021,6 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
2027static void efx_set_rx_mode(struct net_device *net_dev) 2021static void efx_set_rx_mode(struct net_device *net_dev)
2028{ 2022{
2029 struct efx_nic *efx = netdev_priv(net_dev); 2023 struct efx_nic *efx = netdev_priv(net_dev);
2030 struct netdev_hw_addr *ha;
2031 union efx_multicast_hash *mc_hash = &efx->multicast_hash;
2032 u32 crc;
2033 int bit;
2034
2035 efx->promiscuous = !!(net_dev->flags & IFF_PROMISC);
2036
2037 /* Build multicast hash table */
2038 if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
2039 memset(mc_hash, 0xff, sizeof(*mc_hash));
2040 } else {
2041 memset(mc_hash, 0x00, sizeof(*mc_hash));
2042 netdev_for_each_mc_addr(ha, net_dev) {
2043 crc = ether_crc_le(ETH_ALEN, ha->addr);
2044 bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
2045 __set_bit_le(bit, mc_hash);
2046 }
2047
2048 /* Broadcast packets go through the multicast hash filter.
2049 * ether_crc_le() of the broadcast address is 0xbe2612ff
2050 * so we always add bit 0xff to the mask.
2051 */
2052 __set_bit_le(0xff, mc_hash);
2053 }
2054 2024
2055 if (efx->port_enabled) 2025 if (efx->port_enabled)
2056 queue_work(efx->workqueue, &efx->mac_work); 2026 queue_work(efx->workqueue, &efx->mac_work);
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index 6ea28f8e8792..983e7f5c4e11 100644
--- a/drivers/net/ethernet/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -764,7 +764,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
764 FRF_AB_XM_RXEN, 1, 764 FRF_AB_XM_RXEN, 1,
765 FRF_AB_XM_AUTO_DEPAD, 0, 765 FRF_AB_XM_AUTO_DEPAD, 0,
766 FRF_AB_XM_ACPT_ALL_MCAST, 1, 766 FRF_AB_XM_ACPT_ALL_MCAST, 1,
767 FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous, 767 FRF_AB_XM_ACPT_ALL_UCAST, !efx->unicast_filter,
768 FRF_AB_XM_PASS_CRC_ERR, 1); 768 FRF_AB_XM_PASS_CRC_ERR, 1);
769 efx_writeo(efx, &reg, FR_AB_XM_RX_CFG); 769 efx_writeo(efx, &reg, FR_AB_XM_RX_CFG);
770 770
@@ -864,6 +864,8 @@ static int falcon_reconfigure_xmac(struct efx_nic *efx)
864{ 864{
865 struct falcon_nic_data *nic_data = efx->nic_data; 865 struct falcon_nic_data *nic_data = efx->nic_data;
866 866
867 efx_farch_filter_sync_rx_mode(efx);
868
867 falcon_reconfigure_xgxs_core(efx); 869 falcon_reconfigure_xgxs_core(efx);
868 falcon_reconfigure_xmac_core(efx); 870 falcon_reconfigure_xmac_core(efx);
869 871
@@ -1081,7 +1083,7 @@ static void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
1081 EFX_POPULATE_OWORD_5(reg, 1083 EFX_POPULATE_OWORD_5(reg,
1082 FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */, 1084 FRF_AB_MAC_XOFF_VAL, 0xffff /* max pause time */,
1083 FRF_AB_MAC_BCAD_ACPT, 1, 1085 FRF_AB_MAC_BCAD_ACPT, 1,
1084 FRF_AB_MAC_UC_PROM, efx->promiscuous, 1086 FRF_AB_MAC_UC_PROM, !efx->unicast_filter,
1085 FRF_AB_MAC_LINK_STATUS, 1, /* always set */ 1087 FRF_AB_MAC_LINK_STATUS, 1, /* always set */
1086 FRF_AB_MAC_SPEED, link_speed); 1088 FRF_AB_MAC_SPEED, link_speed);
1087 /* On B0, MAC backpressure can be disabled and packets get 1089 /* On B0, MAC backpressure can be disabled and packets get
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index 1e21e51a808b..b6af8f4cc704 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -14,6 +14,7 @@
14#include <linux/pci.h> 14#include <linux/pci.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/seq_file.h> 16#include <linux/seq_file.h>
17#include <linux/crc32.h>
17#include "net_driver.h" 18#include "net_driver.h"
18#include "bitfield.h" 19#include "bitfield.h"
19#include "efx.h" 20#include "efx.h"
@@ -2906,3 +2907,36 @@ bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
2906} 2907}
2907 2908
2908#endif /* CONFIG_RFS_ACCEL */ 2909#endif /* CONFIG_RFS_ACCEL */
2910
2911void efx_farch_filter_sync_rx_mode(struct efx_nic *efx)
2912{
2913 struct net_device *net_dev = efx->net_dev;
2914 struct netdev_hw_addr *ha;
2915 union efx_multicast_hash *mc_hash = &efx->multicast_hash;
2916 u32 crc;
2917 int bit;
2918
2919 netif_addr_lock_bh(net_dev);
2920
2921 efx->unicast_filter = !(net_dev->flags & IFF_PROMISC);
2922
2923 /* Build multicast hash table */
2924 if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
2925 memset(mc_hash, 0xff, sizeof(*mc_hash));
2926 } else {
2927 memset(mc_hash, 0x00, sizeof(*mc_hash));
2928 netdev_for_each_mc_addr(ha, net_dev) {
2929 crc = ether_crc_le(ETH_ALEN, ha->addr);
2930 bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
2931 __set_bit_le(bit, mc_hash);
2932 }
2933
2934 /* Broadcast packets go through the multicast hash filter.
2935 * ether_crc_le() of the broadcast address is 0xbe2612ff
2936 * so we always add bit 0xff to the mask.
2937 */
2938 __set_bit_le(0xff, mc_hash);
2939 }
2940
2941 netif_addr_unlock_bh(net_dev);
2942}
diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c
index 30e8a1936fc2..42d52f34ad79 100644
--- a/drivers/net/ethernet/sfc/mcdi_port.c
+++ b/drivers/net/ethernet/sfc/mcdi_port.c
@@ -861,7 +861,7 @@ void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
861 861
862int efx_mcdi_set_mac(struct efx_nic *efx) 862int efx_mcdi_set_mac(struct efx_nic *efx)
863{ 863{
864 u32 reject, fcntl; 864 u32 fcntl;
865 MCDI_DECLARE_BUF(cmdbytes, MC_CMD_SET_MAC_IN_LEN); 865 MCDI_DECLARE_BUF(cmdbytes, MC_CMD_SET_MAC_IN_LEN);
866 866
867 BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0); 867 BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
@@ -873,12 +873,9 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
873 EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); 873 EFX_MAX_FRAME_LEN(efx->net_dev->mtu));
874 MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0); 874 MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0);
875 875
876 /* The MCDI command provides for controlling accept/reject 876 /* Set simple MAC filter for Siena */
877 * of broadcast packets too, but the driver doesn't currently 877 MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_REJECT,
878 * expose this. */ 878 SET_MAC_IN_REJECT_UNCST, efx->unicast_filter);
879 reject = (efx->promiscuous) ? 0 :
880 (1 << MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN);
881 MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_REJECT, reject);
882 879
883 switch (efx->wanted_fc) { 880 switch (efx->wanted_fc) {
884 case EFX_FC_RX | EFX_FC_TX: 881 case EFX_FC_RX | EFX_FC_TX:
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index d35ce1410376..555dd013bda7 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -753,8 +753,10 @@ struct vfdi_status;
753 * @link_advertising: Autonegotiation advertising flags 753 * @link_advertising: Autonegotiation advertising flags
754 * @link_state: Current state of the link 754 * @link_state: Current state of the link
755 * @n_link_state_changes: Number of times the link has changed state 755 * @n_link_state_changes: Number of times the link has changed state
756 * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. 756 * @unicast_filter: Flag for Falcon-arch simple unicast filter.
757 * @multicast_hash: Multicast hash table 757 * Protected by @mac_lock.
758 * @multicast_hash: Multicast hash table for Falcon-arch.
759 * Protected by @mac_lock.
758 * @wanted_fc: Wanted flow control flags 760 * @wanted_fc: Wanted flow control flags
759 * @fc_disable: When non-zero flow control is disabled. Typically used to 761 * @fc_disable: When non-zero flow control is disabled. Typically used to
760 * ensure that network back pressure doesn't delay dma queue flushes. 762 * ensure that network back pressure doesn't delay dma queue flushes.
@@ -892,7 +894,7 @@ struct efx_nic {
892 struct efx_link_state link_state; 894 struct efx_link_state link_state;
893 unsigned int n_link_state_changes; 895 unsigned int n_link_state_changes;
894 896
895 bool promiscuous; 897 bool unicast_filter;
896 union efx_multicast_hash multicast_hash; 898 union efx_multicast_hash multicast_hash;
897 u8 wanted_fc; 899 u8 wanted_fc;
898 unsigned fc_disable; 900 unsigned fc_disable;
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index 69298c918e97..8baf6a1d2ac8 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -431,6 +431,7 @@ extern s32 efx_farch_filter_rfs_insert(struct efx_nic *efx,
431extern bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id, 431extern bool efx_farch_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
432 unsigned int index); 432 unsigned int index);
433#endif 433#endif
434extern void efx_farch_filter_sync_rx_mode(struct efx_nic *efx);
434 435
435extern bool efx_nic_event_present(struct efx_channel *channel); 436extern bool efx_nic_event_present(struct efx_channel *channel);
436 437
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index 5120cd8f706b..1be81e431f07 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -503,6 +503,8 @@ static int siena_mac_reconfigure(struct efx_nic *efx)
503 MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST + 503 MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST +
504 sizeof(efx->multicast_hash)); 504 sizeof(efx->multicast_hash));
505 505
506 efx_farch_filter_sync_rx_mode(efx);
507
506 WARN_ON(!mutex_is_locked(&efx->mac_lock)); 508 WARN_ON(!mutex_is_locked(&efx->mac_lock));
507 509
508 rc = efx_mcdi_set_mac(efx); 510 rc = efx_mcdi_set_mac(efx);