summaryrefslogtreecommitdiff
path: root/drivers/net/sfc/efx.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-25 16:12:16 +0000
committerDavid S. Miller <davem@davemloft.net>2009-11-26 15:59:49 -0800
commit8be4f3e6f7b670529bd67aa1f0319bec1e29ebcf (patch)
tree1d92fa5b1b1046f052c20d8bdaa17ffce6881446 /drivers/net/sfc/efx.c
parent9007b9fa368b172e6b9a985899080fbebb7d3204 (diff)
sfc: Change MAC promiscuity and multicast hash at the same time
From: Steve Hodgson <shodgson@solarflare.com> Currently we can set multicast hash immediately (in atomic context) but must delay setting MAC promiscuity. There is not that much point in deferring one but not the other, and setting the multicast hash on Siena will involve a firmware request. So process them both in efx_mac_work(). Also, set the broadcast bit in the multicast hash in efx_set_multicast_list(), since this is required for both Falcon and Siena. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/efx.c')
-rw-r--r--drivers/net/sfc/efx.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 15616dd9ed41..1009d1eeba82 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -688,11 +688,18 @@ static void efx_phy_work(struct work_struct *data)
mutex_unlock(&efx->mac_lock);
}
+/* Asynchronous work item for changing MAC promiscuity and multicast
+ * hash. Avoid a drain/rx_ingress enable by reconfiguring the current
+ * MAC directly. */
static void efx_mac_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, mac_work);
mutex_lock(&efx->mac_lock);
+ if (efx->port_enabled) {
+ falcon_push_multicast_hash(efx);
+ efx->mac_op->reconfigure(efx);
+ }
mutex_unlock(&efx->mac_lock);
}
@@ -771,7 +778,12 @@ static void efx_start_port(struct efx_nic *efx)
mutex_lock(&efx->mac_lock);
efx->port_enabled = true;
- __efx_reconfigure_port(efx);
+
+ /* efx_mac_work() might have been scheduled after efx_stop_port(),
+ * and then cancelled by efx_flush_all() */
+ falcon_push_multicast_hash(efx);
+ efx->mac_op->reconfigure(efx);
+
mutex_unlock(&efx->mac_lock);
}
@@ -1534,16 +1546,14 @@ static void efx_set_multicast_list(struct net_device *net_dev)
struct efx_nic *efx = netdev_priv(net_dev);
struct dev_mc_list *mc_list = net_dev->mc_list;
union efx_multicast_hash *mc_hash = &efx->multicast_hash;
- bool promiscuous = !!(net_dev->flags & IFF_PROMISC);
- bool changed = (efx->promiscuous != promiscuous);
u32 crc;
int bit;
int i;
- efx->promiscuous = promiscuous;
+ efx->promiscuous = !!(net_dev->flags & IFF_PROMISC);
/* Build multicast hash table */
- if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+ if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
memset(mc_hash, 0xff, sizeof(*mc_hash));
} else {
memset(mc_hash, 0x00, sizeof(*mc_hash));
@@ -1553,17 +1563,17 @@ static void efx_set_multicast_list(struct net_device *net_dev)
set_bit_le(bit, mc_hash->byte);
mc_list = mc_list->next;
}
- }
- if (!efx->port_enabled)
- /* Delay pushing settings until efx_start_port() */
- return;
-
- if (changed)
- queue_work(efx->workqueue, &efx->phy_work);
+ /* Broadcast packets go through the multicast hash filter.
+ * ether_crc_le() of the broadcast address is 0xbe2612ff
+ * so we always add bit 0xff to the mask.
+ */
+ set_bit_le(0xff, mc_hash->byte);
+ }
- /* Create and activate new global multicast hash table */
- falcon_set_multicast_hash(efx);
+ if (efx->port_enabled)
+ queue_work(efx->workqueue, &efx->mac_work);
+ /* Otherwise efx_start_port() will do this */
}
static const struct net_device_ops efx_netdev_ops = {