sfc: Change MAC promiscuity and multicast hash at the same time
[pandora-kernel.git] / drivers / net / sfc / efx.c
index 0d0243b..1009d1e 100644 (file)
 #include <linux/ethtool.h>
 #include <linux/topology.h>
 #include "net_driver.h"
-#include "ethtool.h"
-#include "tx.h"
-#include "rx.h"
 #include "efx.h"
 #include "mdio_10g.h"
 #include "falcon.h"
 
+/**************************************************************************
+ *
+ * Type name strings
+ *
+ **************************************************************************
+ */
+
+/* Loopback mode names (see LOOPBACK_MODE()) */
+const unsigned int efx_loopback_mode_max = LOOPBACK_MAX;
+const char *efx_loopback_mode_names[] = {
+       [LOOPBACK_NONE]         = "NONE",
+       [LOOPBACK_GMAC]         = "GMAC",
+       [LOOPBACK_XGMII]        = "XGMII",
+       [LOOPBACK_XGXS]         = "XGXS",
+       [LOOPBACK_XAUI]         = "XAUI",
+       [LOOPBACK_GPHY]         = "GPHY",
+       [LOOPBACK_PHYXS]        = "PHYXS",
+       [LOOPBACK_PCS]          = "PCS",
+       [LOOPBACK_PMAPMD]       = "PMA/PMD",
+       [LOOPBACK_NETWORK]      = "NETWORK",
+};
+
+/* Interrupt mode names (see INT_MODE())) */
+const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX;
+const char *efx_interrupt_mode_names[] = {
+       [EFX_INT_MODE_MSIX]   = "MSI-X",
+       [EFX_INT_MODE_MSI]    = "MSI",
+       [EFX_INT_MODE_LEGACY] = "legacy",
+};
+
+const unsigned int efx_reset_type_max = RESET_TYPE_MAX;
+const char *efx_reset_type_names[] = {
+       [RESET_TYPE_INVISIBLE]     = "INVISIBLE",
+       [RESET_TYPE_ALL]           = "ALL",
+       [RESET_TYPE_WORLD]         = "WORLD",
+       [RESET_TYPE_DISABLE]       = "DISABLE",
+       [RESET_TYPE_TX_WATCHDOG]   = "TX_WATCHDOG",
+       [RESET_TYPE_INT_ERROR]     = "INT_ERROR",
+       [RESET_TYPE_RX_RECOVERY]   = "RX_RECOVERY",
+       [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH",
+       [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH",
+       [RESET_TYPE_TX_SKIP]       = "TX_SKIP",
+};
+
 #define EFX_MAX_MTU (9 * 1024)
 
 /* RX slow fill workqueue. If memory allocation fails in the fast path,
@@ -145,7 +186,8 @@ static void efx_fini_channels(struct efx_nic *efx);
 
 #define EFX_ASSERT_RESET_SERIALISED(efx)               \
        do {                                            \
-               if (efx->state == STATE_RUNNING)        \
+               if ((efx->state == STATE_RUNNING) ||    \
+                   (efx->state == STATE_DISABLED))     \
                        ASSERT_RTNL();                  \
        } while (0)
 
@@ -543,6 +585,8 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
  */
 static void efx_link_status_changed(struct efx_nic *efx)
 {
+       struct efx_link_state *link_state = &efx->link_state;
+
        /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
         * that no events are triggered between unregister_netdev() and the
         * driver unloading. A more general condition is that NETDEV_CHANGE
@@ -555,19 +599,19 @@ static void efx_link_status_changed(struct efx_nic *efx)
                return;
        }
 
-       if (efx->link_up != netif_carrier_ok(efx->net_dev)) {
+       if (link_state->up != netif_carrier_ok(efx->net_dev)) {
                efx->n_link_state_changes++;
 
-               if (efx->link_up)
+               if (link_state->up)
                        netif_carrier_on(efx->net_dev);
                else
                        netif_carrier_off(efx->net_dev);
        }
 
        /* Status message for kernel log */
-       if (efx->link_up) {
+       if (link_state->up) {
                EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n",
-                        efx->link_speed, efx->link_fd ? "full" : "half",
+                        link_state->speed, link_state->fd ? "full" : "half",
                         efx->net_dev->mtu,
                         (efx->promiscuous ? " [PROMISC]" : ""));
        } else {
@@ -593,6 +637,7 @@ void __efx_reconfigure_port(struct efx_nic *efx)
                netif_addr_unlock_bh(efx->net_dev);
        }
 
+       falcon_stop_nic_stats(efx);
        falcon_deconfigure_mac_wrapper(efx);
 
        /* Reconfigure the PHY, disabling transmit in mac level loopback. */
@@ -607,6 +652,8 @@ void __efx_reconfigure_port(struct efx_nic *efx)
 
        efx->mac_op->reconfigure(efx);
 
+       falcon_start_nic_stats(efx);
+
        /* Inform kernel of loss/gain of carrier */
        efx_link_status_changed(efx);
        return;
@@ -641,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);
 }
 
@@ -693,23 +745,26 @@ static int efx_init_port(struct efx_nic *efx)
 
        EFX_LOG(efx, "init port\n");
 
+       mutex_lock(&efx->mac_lock);
+
        rc = efx->phy_op->init(efx);
        if (rc)
-               return rc;
-       mutex_lock(&efx->mac_lock);
+               goto fail1;
        efx->phy_op->reconfigure(efx);
        rc = falcon_switch_mac(efx);
-       mutex_unlock(&efx->mac_lock);
        if (rc)
-               goto fail;
+               goto fail2;
        efx->mac_op->reconfigure(efx);
 
        efx->port_initialized = true;
-       efx_stats_enable(efx);
+
+       mutex_unlock(&efx->mac_lock);
        return 0;
 
-fail:
+fail2:
        efx->phy_op->fini(efx);
+fail1:
+       mutex_unlock(&efx->mac_lock);
        return rc;
 }
 
@@ -723,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);
 }
 
@@ -754,11 +813,10 @@ static void efx_fini_port(struct efx_nic *efx)
        if (!efx->port_initialized)
                return;
 
-       efx_stats_disable(efx);
        efx->phy_op->fini(efx);
        efx->port_initialized = false;
 
-       efx->link_up = false;
+       efx->link_state.up = false;
        efx_link_status_changed(efx);
 }
 
@@ -1110,6 +1168,8 @@ static void efx_start_all(struct efx_nic *efx)
        if (efx->state == STATE_RUNNING)
                queue_delayed_work(efx->workqueue, &efx->monitor_work,
                                   efx_monitor_interval);
+
+       falcon_start_nic_stats(efx);
 }
 
 /* Flush all delayed work. Should only be called when no more delayed work
@@ -1147,6 +1207,8 @@ static void efx_stop_all(struct efx_nic *efx)
        if (!efx->port_enabled)
                return;
 
+       falcon_stop_nic_stats(efx);
+
        /* Disable interrupts and wait for ISR to complete */
        falcon_disable_interrupts(efx);
        if (efx->legacy_irq)
@@ -1193,19 +1255,6 @@ static void efx_remove_all(struct efx_nic *efx)
        efx_remove_nic(efx);
 }
 
-/* A convinience function to safely flush all the queues */
-void efx_flush_queues(struct efx_nic *efx)
-{
-       EFX_ASSERT_RESET_SERIALISED(efx);
-
-       efx_stop_all(efx);
-
-       efx_fini_channels(efx);
-       efx_init_channels(efx);
-
-       efx_start_all(efx);
-}
-
 /**************************************************************************
  *
  * Interrupt moderation
@@ -1253,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());
@@ -1265,15 +1313,7 @@ static void efx_monitor(struct work_struct *data)
                goto out_requeue;
        if (!efx->port_enabled)
                goto out_unlock;
-       rc = efx->board_info.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);
@@ -1403,20 +1443,6 @@ static int efx_net_stop(struct net_device *net_dev)
        return 0;
 }
 
-void efx_stats_disable(struct efx_nic *efx)
-{
-       spin_lock(&efx->stats_lock);
-       ++efx->stats_disable_count;
-       spin_unlock(&efx->stats_lock);
-}
-
-void efx_stats_enable(struct efx_nic *efx)
-{
-       spin_lock(&efx->stats_lock);
-       --efx->stats_disable_count;
-       spin_unlock(&efx->stats_lock);
-}
-
 /* Context: process, dev_base_lock or RTNL held, non-blocking. */
 static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
 {
@@ -1424,17 +1450,9 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
        struct efx_mac_stats *mac_stats = &efx->mac_stats;
        struct net_device_stats *stats = &net_dev->stats;
 
-       /* Update stats if possible, but do not wait if another thread
-        * is updating them or if MAC stats fetches are temporarily
-        * disabled; slightly stale stats are acceptable.
-        */
-       if (!spin_trylock(&efx->stats_lock))
-               return stats;
-       if (!efx->stats_disable_count) {
-               efx->mac_op->update_stats(efx);
-               falcon_update_nic_stats(efx);
-       }
-       spin_unlock(&efx->stats_lock);
+       spin_lock_bh(&efx->stats_lock);
+       falcon_update_nic_stats(efx);
+       spin_unlock_bh(&efx->stats_lock);
 
        stats->rx_packets = mac_stats->rx_packets;
        stats->tx_packets = mac_stats->tx_packets;
@@ -1528,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));
@@ -1547,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 = {
@@ -1691,7 +1707,6 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method,
 {
        EFX_ASSERT_RESET_SERIALISED(efx);
 
-       efx_stats_disable(efx);
        efx_stop_all(efx);
        mutex_lock(&efx->mac_lock);
        mutex_lock(&efx->spi_lock);
@@ -1741,10 +1756,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
        mutex_unlock(&efx->spi_lock);
        mutex_unlock(&efx->mac_lock);
 
-       if (ok) {
+       if (ok)
                efx_start_all(efx);
-               efx_stats_enable(efx);
-       }
        return rc;
 }
 
@@ -1773,7 +1786,7 @@ static int efx_reset(struct efx_nic *efx)
                goto out_unlock;
        }
 
-       EFX_INFO(efx, "resetting (%d)\n", method);
+       EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
 
        efx_reset_down(efx, method, &ecmd);
 
@@ -1852,9 +1865,10 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
        }
 
        if (method != type)
-               EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method);
+               EFX_LOG(efx, "scheduling %s reset for %s\n",
+                       RESET_TYPE(method), RESET_TYPE(type));
        else
-               EFX_LOG(efx, "scheduling reset (%d)\n", method);
+               EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method));
 
        efx->reset_pending = method;
 
@@ -1878,7 +1892,7 @@ static struct pci_device_id efx_pci_table[] __devinitdata = {
 
 /**************************************************************************
  *
- * Dummy PHY/MAC/Board operations
+ * Dummy PHY/MAC operations
  *
  * Can be used for some unimplemented operations
  * Needed so all function pointers are valid and do not have to be tested
@@ -1890,12 +1904,12 @@ int efx_port_dummy_op_int(struct efx_nic *efx)
        return 0;
 }
 void efx_port_dummy_op_void(struct efx_nic *efx) {}
-void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {}
+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 = {
@@ -1906,15 +1920,6 @@ static struct efx_phy_operations efx_dummy_phy_operations = {
        .clear_interrupt = efx_port_dummy_op_void,
 };
 
-static struct efx_board efx_dummy_board_info = {
-       .init           = efx_port_dummy_op_int,
-       .init_leds      = efx_port_dummy_op_void,
-       .set_id_led     = efx_port_dummy_op_blink,
-       .monitor        = efx_port_dummy_op_int,
-       .blink          = efx_port_dummy_op_blink,
-       .fini           = efx_port_dummy_op_void,
-};
-
 /**************************************************************************
  *
  * Data housekeeping
@@ -1943,13 +1948,11 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
        efx->state = STATE_INIT;
        efx->reset_pending = RESET_TYPE_NONE;
        strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
-       efx->board_info = efx_dummy_board_info;
 
        efx->net_dev = net_dev;
        efx->rx_checksum_enabled = true;
        spin_lock_init(&efx->netif_stop_lock);
        spin_lock_init(&efx->stats_lock);
-       efx->stats_disable_count = 1;
        mutex_init(&efx->mac_lock);
        efx->mac_op = &efx_dummy_mac_operations;
        efx->phy_op = &efx_dummy_phy_operations;
@@ -2025,10 +2028,6 @@ static void efx_pci_remove_main(struct efx_nic *efx)
        falcon_fini_interrupt(efx);
        efx_fini_channels(efx);
        efx_fini_port(efx);
-
-       /* Shutdown the board, then the NIC and board state */
-       efx->board_info.fini(efx);
-
        efx_fini_napi(efx);
        efx_remove_all(efx);
 }
@@ -2088,39 +2087,30 @@ static int efx_pci_probe_main(struct efx_nic *efx)
        if (rc)
                goto fail2;
 
-       /* Initialise the board */
-       rc = efx->board_info.init(efx);
-       if (rc) {
-               EFX_ERR(efx, "failed to initialise board\n");
-               goto fail3;
-       }
-
        rc = falcon_init_nic(efx);
        if (rc) {
                EFX_ERR(efx, "failed to initialise NIC\n");
-               goto fail4;
+               goto fail3;
        }
 
        rc = efx_init_port(efx);
        if (rc) {
                EFX_ERR(efx, "failed to initialise port\n");
-               goto fail5;
+               goto fail4;
        }
 
        efx_init_channels(efx);
 
        rc = falcon_init_interrupt(efx);
        if (rc)
-               goto fail6;
+               goto fail5;
 
        return 0;
 
- fail6:
+ fail5:
        efx_fini_channels(efx);
        efx_fini_port(efx);
- fail5:
  fail4:
-       efx->board_info.fini(efx);
  fail3:
        efx_fini_napi(efx);
  fail2:
@@ -2204,9 +2194,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
                goto fail4;
        }
 
-       /* Switch to the running state before we expose the device to
-        * the OS.  This is to ensure that the initial gathering of
-        * MAC stats succeeds. */
+       /* Switch to the running state before we expose the device to the OS,
+        * so that dev_open()|efx_start_all() will actually start the device */
        efx->state = STATE_RUNNING;
 
        rc = efx_register_netdev(efx);