e1000e: function pointers for ethtool set/get offloads
[safe/jmp/linux-2.6] / drivers / net / e1000e / ethtool.c
index e48956d..3d73f20 100644 (file)
 
 #include "e1000.h"
 
+enum {NETDEV_STATS, E1000_STATS};
+
 struct e1000_stats {
        char stat_string[ETH_GSTRING_LEN];
+       int type;
        int sizeof_stat;
        int stat_offset;
 };
 
-#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
-                     offsetof(struct e1000_adapter, m)
+#define E1000_STAT(m)          E1000_STATS, \
+                               sizeof(((struct e1000_adapter *)0)->m), \
+                               offsetof(struct e1000_adapter, m)
+#define E1000_NETDEV_STAT(m)   NETDEV_STATS, \
+                               sizeof(((struct net_device *)0)->m), \
+                               offsetof(struct net_device, m)
+
 static const struct e1000_stats e1000_gstrings_stats[] = {
        { "rx_packets", E1000_STAT(stats.gprc) },
        { "tx_packets", E1000_STAT(stats.gptc) },
@@ -52,21 +60,21 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
        { "tx_broadcast", E1000_STAT(stats.bptc) },
        { "rx_multicast", E1000_STAT(stats.mprc) },
        { "tx_multicast", E1000_STAT(stats.mptc) },
-       { "rx_errors", E1000_STAT(net_stats.rx_errors) },
-       { "tx_errors", E1000_STAT(net_stats.tx_errors) },
-       { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+       { "rx_errors", E1000_NETDEV_STAT(stats.rx_errors) },
+       { "tx_errors", E1000_NETDEV_STAT(stats.tx_errors) },
+       { "tx_dropped", E1000_NETDEV_STAT(stats.tx_dropped) },
        { "multicast", E1000_STAT(stats.mprc) },
        { "collisions", E1000_STAT(stats.colc) },
-       { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
-       { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+       { "rx_length_errors", E1000_NETDEV_STAT(stats.rx_length_errors) },
+       { "rx_over_errors", E1000_NETDEV_STAT(stats.rx_over_errors) },
        { "rx_crc_errors", E1000_STAT(stats.crcerrs) },
-       { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+       { "rx_frame_errors", E1000_NETDEV_STAT(stats.rx_frame_errors) },
        { "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
        { "rx_missed_errors", E1000_STAT(stats.mpc) },
        { "tx_aborted_errors", E1000_STAT(stats.ecol) },
        { "tx_carrier_errors", E1000_STAT(stats.tncrs) },
-       { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
-       { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+       { "tx_fifo_errors", E1000_NETDEV_STAT(stats.tx_fifo_errors) },
+       { "tx_heartbeat_errors", E1000_NETDEV_STAT(stats.tx_heartbeat_errors) },
        { "tx_window_errors", E1000_STAT(stats.latecol) },
        { "tx_abort_late_coll", E1000_STAT(stats.latecol) },
        { "tx_deferred_ok", E1000_STAT(stats.dc) },
@@ -167,6 +175,15 @@ static int e1000_get_settings(struct net_device *netdev,
 
        ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
                         hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+       /* MDI-X => 2; MDI =>1; Invalid =>0 */
+       if ((hw->phy.media_type == e1000_media_type_copper) &&
+           !hw->mac.get_link_status)
+               ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
+                                                     ETH_TP_MDI;
+       else
+               ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
+
        return 0;
 }
 
@@ -318,10 +335,18 @@ static int e1000_set_pauseparam(struct net_device *netdev,
 
                hw->fc.current_mode = hw->fc.requested_mode;
 
-               retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
-                         hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw));
+               if (hw->phy.media_type == e1000_media_type_fiber) {
+                       retval = hw->mac.ops.setup_link(hw);
+                       /* implicit goto out */
+               } else {
+                       retval = e1000e_force_mac_fc(hw);
+                       if (retval)
+                               goto out;
+                       e1000e_set_fc_watermarks(hw);
+               }
        }
 
+out:
        clear_bit(__E1000_RESETTING, &adapter->state);
        return retval;
 }
@@ -579,7 +604,9 @@ static int e1000_set_eeprom(struct net_device *netdev,
         * and flush shadow RAM for applicable controllers
         */
        if ((first_word <= NVM_CHECKSUM_REG) ||
-           (hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573))
+           (hw->mac.type == e1000_82583) ||
+           (hw->mac.type == e1000_82574) ||
+           (hw->mac.type == e1000_82573))
                ret_val = e1000e_update_nvm_checksum(hw);
 
 out:
@@ -776,6 +803,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
        u32 after;
        u32 i;
        u32 toggle;
+       u32 mask;
 
        /*
         * The status register is Read Only, so a write should fail.
@@ -788,16 +816,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
        case e1000_80003es2lan:
                toggle = 0x7FFFF3FF;
                break;
-       case e1000_82573:
-       case e1000_82574:
-       case e1000_ich8lan:
-       case e1000_ich9lan:
-       case e1000_ich10lan:
+        default:
                toggle = 0x7FFFF033;
                break;
-       default:
-               toggle = 0xFFFFF833;
-               break;
        }
 
        before = er32(STATUS);
@@ -843,11 +864,18 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
        REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
        REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
+       mask = 0x8003FFFF;
+       switch (mac->type) {
+       case e1000_ich10lan:
+       case e1000_pchlan:
+               mask |= (1 << 18);
+               break;
+       default:
+               break;
+       }
        for (i = 0; i < mac->rar_entry_count; i++)
                REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
-                                      ((mac->type == e1000_ich10lan) ?
-                                          0x8007FFFF : 0x8003FFFF),
-                                      0xFFFFFFFF);
+                                      mask, 0xFFFFFFFF);
 
        for (i = 0; i < mac->mta_reg_count; i++)
                REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
@@ -911,10 +939,10 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                e1000e_set_interrupt_capability(adapter);
        }
        /* Hook up test interrupt handler just for this test */
-       if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
+       if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
                         netdev)) {
                shared_int = 0;
-       } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+       } else if (request_irq(irq, e1000_test_intr, IRQF_SHARED,
                 netdev->name, netdev)) {
                *data = 1;
                ret_val = -1;
@@ -1589,7 +1617,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
        *data = 0;
        if (hw->phy.media_type == e1000_media_type_internal_serdes) {
                int i = 0;
-               hw->mac.serdes_has_link = 0;
+               hw->mac.serdes_has_link = false;
 
                /*
                 * On some blade server designs, link establishment
@@ -1751,12 +1779,11 @@ static int e1000_set_wol(struct net_device *netdev,
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (wol->wolopts & WAKE_MAGICSECURE)
-               return -EOPNOTSUPP;
-
        if (!(adapter->flags & FLAG_HAS_WOL) ||
-           !device_can_wakeup(&adapter->pdev->dev))
-               return wol->wolopts ? -EOPNOTSUPP : 0;
+           !device_can_wakeup(&adapter->pdev->dev) ||
+           (wol->wolopts & ~(WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
+                             WAKE_MAGIC | WAKE_PHY | WAKE_ARP)))
+               return -EOPNOTSUPP;
 
        /* these settings will always override what we currently have */
        adapter->wol = 0;
@@ -1785,15 +1812,22 @@ static int e1000_set_wol(struct net_device *netdev,
 /* bit defines for adapter->led_status */
 #define E1000_LED_ON           0
 
-static void e1000_led_blink_callback(unsigned long data)
+static void e1000e_led_blink_task(struct work_struct *work)
 {
-       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+       struct e1000_adapter *adapter = container_of(work,
+                                       struct e1000_adapter, led_blink_task);
 
        if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
                adapter->hw.mac.ops.led_off(&adapter->hw);
        else
                adapter->hw.mac.ops.led_on(&adapter->hw);
+}
 
+static void e1000_led_blink_callback(unsigned long data)
+{
+       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+       schedule_work(&adapter->led_blink_task);
        mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
 }
 
@@ -1806,7 +1840,10 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
                data = INT_MAX;
 
        if ((hw->phy.type == e1000_phy_ife) ||
+           (hw->mac.type == e1000_pchlan) ||
+           (hw->mac.type == e1000_82583) ||
            (hw->mac.type == e1000_82574)) {
+               INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
                if (!adapter->blink_timer.function) {
                        init_timer(&adapter->blink_timer);
                        adapter->blink_timer.function =
@@ -1885,10 +1922,21 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        int i;
+       char *p = NULL;
 
        e1000e_update_stats(adapter);
        for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
-               char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
+               switch (e1000_gstrings_stats[i].type) {
+               case NETDEV_STATS:
+                       p = (char *) netdev +
+                                       e1000_gstrings_stats[i].stat_offset;
+                       break;
+               case E1000_STATS:
+                       p = (char *) adapter +
+                                       e1000_gstrings_stats[i].stat_offset;
+                       break;
+               }
+
                data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
                        sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
        }
@@ -1948,6 +1996,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
        .get_sset_count         = e1000e_get_sset_count,
        .get_coalesce           = e1000_get_coalesce,
        .set_coalesce           = e1000_set_coalesce,
+       .get_flags              = ethtool_op_get_flags,
+       .set_flags              = ethtool_op_set_flags,
 };
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)