diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-25 11:12:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-26 18:59:49 -0500 |
commit | 8be4f3e6f7b670529bd67aa1f0319bec1e29ebcf (patch) | |
tree | 1d92fa5b1b1046f052c20d8bdaa17ffce6881446 | |
parent | 9007b9fa368b172e6b9a985899080fbebb7d3204 (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>
-rw-r--r-- | drivers/net/sfc/efx.c | 38 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.c | 10 | ||||
-rw-r--r-- | drivers/net/sfc/falcon.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 2 |
4 files changed, 29 insertions, 23 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) | |||
688 | mutex_unlock(&efx->mac_lock); | 688 | mutex_unlock(&efx->mac_lock); |
689 | } | 689 | } |
690 | 690 | ||
691 | /* Asynchronous work item for changing MAC promiscuity and multicast | ||
692 | * hash. Avoid a drain/rx_ingress enable by reconfiguring the current | ||
693 | * MAC directly. */ | ||
691 | static void efx_mac_work(struct work_struct *data) | 694 | static void efx_mac_work(struct work_struct *data) |
692 | { | 695 | { |
693 | struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); | 696 | struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); |
694 | 697 | ||
695 | mutex_lock(&efx->mac_lock); | 698 | mutex_lock(&efx->mac_lock); |
699 | if (efx->port_enabled) { | ||
700 | falcon_push_multicast_hash(efx); | ||
701 | efx->mac_op->reconfigure(efx); | ||
702 | } | ||
696 | mutex_unlock(&efx->mac_lock); | 703 | mutex_unlock(&efx->mac_lock); |
697 | } | 704 | } |
698 | 705 | ||
@@ -771,7 +778,12 @@ static void efx_start_port(struct efx_nic *efx) | |||
771 | 778 | ||
772 | mutex_lock(&efx->mac_lock); | 779 | mutex_lock(&efx->mac_lock); |
773 | efx->port_enabled = true; | 780 | efx->port_enabled = true; |
774 | __efx_reconfigure_port(efx); | 781 | |
782 | /* efx_mac_work() might have been scheduled after efx_stop_port(), | ||
783 | * and then cancelled by efx_flush_all() */ | ||
784 | falcon_push_multicast_hash(efx); | ||
785 | efx->mac_op->reconfigure(efx); | ||
786 | |||
775 | mutex_unlock(&efx->mac_lock); | 787 | mutex_unlock(&efx->mac_lock); |
776 | } | 788 | } |
777 | 789 | ||
@@ -1534,16 +1546,14 @@ static void efx_set_multicast_list(struct net_device *net_dev) | |||
1534 | struct efx_nic *efx = netdev_priv(net_dev); | 1546 | struct efx_nic *efx = netdev_priv(net_dev); |
1535 | struct dev_mc_list *mc_list = net_dev->mc_list; | 1547 | struct dev_mc_list *mc_list = net_dev->mc_list; |
1536 | union efx_multicast_hash *mc_hash = &efx->multicast_hash; | 1548 | union efx_multicast_hash *mc_hash = &efx->multicast_hash; |
1537 | bool promiscuous = !!(net_dev->flags & IFF_PROMISC); | ||
1538 | bool changed = (efx->promiscuous != promiscuous); | ||
1539 | u32 crc; | 1549 | u32 crc; |
1540 | int bit; | 1550 | int bit; |
1541 | int i; | 1551 | int i; |
1542 | 1552 | ||
1543 | efx->promiscuous = promiscuous; | 1553 | efx->promiscuous = !!(net_dev->flags & IFF_PROMISC); |
1544 | 1554 | ||
1545 | /* Build multicast hash table */ | 1555 | /* Build multicast hash table */ |
1546 | if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) { | 1556 | if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) { |
1547 | memset(mc_hash, 0xff, sizeof(*mc_hash)); | 1557 | memset(mc_hash, 0xff, sizeof(*mc_hash)); |
1548 | } else { | 1558 | } else { |
1549 | memset(mc_hash, 0x00, sizeof(*mc_hash)); | 1559 | memset(mc_hash, 0x00, sizeof(*mc_hash)); |
@@ -1553,17 +1563,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) | |||
1553 | set_bit_le(bit, mc_hash->byte); | 1563 | set_bit_le(bit, mc_hash->byte); |
1554 | mc_list = mc_list->next; | 1564 | mc_list = mc_list->next; |
1555 | } | 1565 | } |
1556 | } | ||
1557 | 1566 | ||
1558 | if (!efx->port_enabled) | 1567 | /* Broadcast packets go through the multicast hash filter. |
1559 | /* Delay pushing settings until efx_start_port() */ | 1568 | * ether_crc_le() of the broadcast address is 0xbe2612ff |
1560 | return; | 1569 | * so we always add bit 0xff to the mask. |
1561 | 1570 | */ | |
1562 | if (changed) | 1571 | set_bit_le(0xff, mc_hash->byte); |
1563 | queue_work(efx->workqueue, &efx->phy_work); | 1572 | } |
1564 | 1573 | ||
1565 | /* Create and activate new global multicast hash table */ | 1574 | if (efx->port_enabled) |
1566 | falcon_set_multicast_hash(efx); | 1575 | queue_work(efx->workqueue, &efx->mac_work); |
1576 | /* Otherwise efx_start_port() will do this */ | ||
1567 | } | 1577 | } |
1568 | 1578 | ||
1569 | static const struct net_device_ops efx_netdev_ops = { | 1579 | static const struct net_device_ops efx_netdev_ops = { |
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index fac534a274c8..e26043eb01b5 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c | |||
@@ -1993,7 +1993,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) | |||
1993 | efx_writeo(efx, ®, FR_AB_MAC_CTRL); | 1993 | efx_writeo(efx, ®, FR_AB_MAC_CTRL); |
1994 | 1994 | ||
1995 | /* Restore the multicast hash registers. */ | 1995 | /* Restore the multicast hash registers. */ |
1996 | falcon_set_multicast_hash(efx); | 1996 | falcon_push_multicast_hash(efx); |
1997 | 1997 | ||
1998 | /* Transmission of pause frames when RX crosses the threshold is | 1998 | /* Transmission of pause frames when RX crosses the threshold is |
1999 | * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. | 1999 | * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. |
@@ -2327,15 +2327,11 @@ void falcon_remove_port(struct efx_nic *efx) | |||
2327 | ************************************************************************** | 2327 | ************************************************************************** |
2328 | */ | 2328 | */ |
2329 | 2329 | ||
2330 | void falcon_set_multicast_hash(struct efx_nic *efx) | 2330 | void falcon_push_multicast_hash(struct efx_nic *efx) |
2331 | { | 2331 | { |
2332 | union efx_multicast_hash *mc_hash = &efx->multicast_hash; | 2332 | union efx_multicast_hash *mc_hash = &efx->multicast_hash; |
2333 | 2333 | ||
2334 | /* Broadcast packets go through the multicast hash filter. | 2334 | WARN_ON(!mutex_is_locked(&efx->mac_lock)); |
2335 | * ether_crc_le() of the broadcast address is 0xbe2612ff | ||
2336 | * so we always add bit 0xff to the mask. | ||
2337 | */ | ||
2338 | set_bit_le(0xff, mc_hash->byte); | ||
2339 | 2335 | ||
2340 | efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); | 2336 | efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); |
2341 | efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); | 2337 | efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); |
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index 9ae1b6c8474e..c70bb084216f 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h | |||
@@ -163,7 +163,7 @@ extern void falcon_remove_nic(struct efx_nic *efx); | |||
163 | extern void falcon_update_nic_stats(struct efx_nic *efx); | 163 | extern void falcon_update_nic_stats(struct efx_nic *efx); |
164 | extern void falcon_start_nic_stats(struct efx_nic *efx); | 164 | extern void falcon_start_nic_stats(struct efx_nic *efx); |
165 | extern void falcon_stop_nic_stats(struct efx_nic *efx); | 165 | extern void falcon_stop_nic_stats(struct efx_nic *efx); |
166 | extern void falcon_set_multicast_hash(struct efx_nic *efx); | 166 | extern void falcon_push_multicast_hash(struct efx_nic *efx); |
167 | extern int falcon_reset_xaui(struct efx_nic *efx); | 167 | extern int falcon_reset_xaui(struct efx_nic *efx); |
168 | 168 | ||
169 | /* Tests */ | 169 | /* Tests */ |
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index cc1a97b0a0d3..ead1c982365b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h | |||
@@ -730,7 +730,7 @@ union efx_multicast_hash { | |||
730 | * @multicast_hash: Multicast hash table | 730 | * @multicast_hash: Multicast hash table |
731 | * @wanted_fc: Wanted flow control flags | 731 | * @wanted_fc: Wanted flow control flags |
732 | * @phy_work: work item for dealing with PHY events | 732 | * @phy_work: work item for dealing with PHY events |
733 | * @mac_work: work item for dealing with MAC events | 733 | * @mac_work: Work item for changing MAC promiscuity and multicast hash |
734 | * @loopback_mode: Loopback status | 734 | * @loopback_mode: Loopback status |
735 | * @loopback_modes: Supported loopback mode bitmask | 735 | * @loopback_modes: Supported loopback mode bitmask |
736 | * @loopback_selftest: Offline self-test private state | 736 | * @loopback_selftest: Offline self-test private state |