sfc: Change MAC promiscuity and multicast hash at the same time
[pandora-kernel.git] / drivers / net / sfc / efx.c
index 41ca5db..1009d1e 100644 (file)
@@ -688,13 +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)
-               efx->mac_op->irq(efx);
+       if (efx->port_enabled) {
+               falcon_push_multicast_hash(efx);
+               efx->mac_op->reconfigure(efx);
+       }
        mutex_unlock(&efx->mac_lock);
 }
 
@@ -773,8 +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_op->irq(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);
 }
 
@@ -1293,7 +1302,6 @@ static void efx_monitor(struct work_struct *data)
 {
        struct efx_nic *efx = container_of(data, struct efx_nic,
                                           monitor_work.work);
-       int rc;
 
        EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
                  raw_smp_processor_id());
@@ -1305,15 +1313,7 @@ static void efx_monitor(struct work_struct *data)
                goto out_requeue;
        if (!efx->port_enabled)
                goto out_unlock;
-       rc = falcon_board(efx)->type->monitor(efx);
-       if (rc) {
-               EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
-                       (rc == -ERANGE) ? "reported fault" : "failed");
-               efx->phy_mode |= PHY_MODE_LOW_POWER;
-               falcon_sim_phy_event(efx);
-       }
-       efx->phy_op->poll(efx);
-       efx->mac_op->poll(efx);
+       falcon_monitor(efx);
 
 out_unlock:
        mutex_unlock(&efx->mac_lock);
@@ -1546,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));
@@ -1565,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 = {
@@ -1912,8 +1910,6 @@ void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
 
 static struct efx_mac_operations efx_dummy_mac_operations = {
        .reconfigure    = efx_port_dummy_op_void,
-       .poll           = efx_port_dummy_op_void,
-       .irq            = efx_port_dummy_op_void,
 };
 
 static struct efx_phy_operations efx_dummy_phy_operations = {