igb: add support for 82576 quad copper adapter
[linux-2.6-block.git] / drivers / net / igb / igb_ethtool.c
index d7bdc6c16d0ea0a3efd410826f5f41334d38392b..fb09c8ad9f0d2c80fc15ba28797fbea04acaa5be 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007 Intel Corporation.
+  Copyright(c) 2007-2009 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -88,6 +88,7 @@ static const struct igb_stats igb_gstrings_stats[] = {
        { "rx_long_byte_count", IGB_STAT(stats.gorc) },
        { "rx_csum_offload_good", IGB_STAT(hw_csum_good) },
        { "rx_csum_offload_errors", IGB_STAT(hw_csum_err) },
+       { "tx_dma_out_of_sync", IGB_STAT(stats.doosync) },
        { "alloc_rx_buff_failed", IGB_STAT(alloc_rx_buff_failed) },
        { "tx_smbus", IGB_STAT(stats.mgptc) },
        { "rx_smbus", IGB_STAT(stats.mgprc) },
@@ -397,7 +398,7 @@ static void igb_get_regs(struct net_device *netdev,
        regs_buff[34] = rd32(E1000_RLPML);
        regs_buff[35] = rd32(E1000_RFCTL);
        regs_buff[36] = rd32(E1000_MRQC);
-       regs_buff[37] = rd32(E1000_VMD_CTL);
+       regs_buff[37] = rd32(E1000_VT_CTL);
 
        /* Transmit */
        regs_buff[38] = rd32(E1000_TCTL);
@@ -855,23 +856,26 @@ static struct igb_reg_test reg_test_82576[] = {
        { E1000_RDBAL(0),  0x100, 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
        { E1000_RDBAH(0),  0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_RDLEN(0),  0x100, 4, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
-       { E1000_RDBAL(4),  0x40,  8, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
-       { E1000_RDBAH(4),  0x40,  8, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
-       { E1000_RDLEN(4),  0x40,  8, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
-       /* Enable all four RX queues before testing. */
-       { E1000_RXDCTL(0), 0x100, 1,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
+       { E1000_RDBAL(4),  0x40, 12, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_RDBAH(4),  0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RDLEN(4),  0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
+       /* Enable all RX queues before testing. */
+       { E1000_RXDCTL(0), 0x100, 4,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
+       { E1000_RXDCTL(4), 0x40, 12,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
        /* RDH is read-only for 82576, only test RDT. */
        { E1000_RDT(0),    0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_RDT(4),    0x40, 12,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_RXDCTL(0), 0x100, 4,  WRITE_NO_TEST, 0, 0 },
+       { E1000_RXDCTL(4), 0x40, 12,  WRITE_NO_TEST, 0, 0 },
        { E1000_FCRTH,     0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
        { E1000_FCTTV,     0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
        { E1000_TIPG,      0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
        { E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
        { E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
        { E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
-       { E1000_TDBAL(4),  0x40, 8,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
-       { E1000_TDBAH(4),  0x40, 8,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
-       { E1000_TDLEN(4),  0x40, 8,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
+       { E1000_TDBAL(4),  0x40, 12,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_TDBAH(4),  0x40, 12,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_TDLEN(4),  0x40, 12,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },
        { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
        { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
        { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
@@ -918,12 +922,13 @@ static struct igb_reg_test reg_test_82575[] = {
 static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
                             int reg, u32 mask, u32 write)
 {
+       struct e1000_hw *hw = &adapter->hw;
        u32 pat, val;
        u32 _test[] =
                {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
        for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {
-               writel((_test[pat] & write), (adapter->hw.hw_addr + reg));
-               val = readl(adapter->hw.hw_addr + reg);
+               wr32(reg, (_test[pat] & write));
+               val = rd32(reg);
                if (val != (_test[pat] & write & mask)) {
                        dev_err(&adapter->pdev->dev, "pattern test reg %04X "
                                "failed: got 0x%08X expected 0x%08X\n",
@@ -938,9 +943,10 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
 static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
                              int reg, u32 mask, u32 write)
 {
+       struct e1000_hw *hw = &adapter->hw;
        u32 val;
-       writel((write & mask), (adapter->hw.hw_addr + reg));
-       val = readl(adapter->hw.hw_addr + reg);
+       wr32(reg, write & mask);
+       val = rd32(reg);
        if ((write & mask) != (val & mask)) {
                dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:"
                        " got 0x%08X expected 0x%08X\n", reg,
@@ -1006,12 +1012,14 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
                for (i = 0; i < test->array_len; i++) {
                        switch (test->test_type) {
                        case PATTERN_TEST:
-                               REG_PATTERN_TEST(test->reg + (i * test->reg_offset),
+                               REG_PATTERN_TEST(test->reg +
+                                               (i * test->reg_offset),
                                                test->mask,
                                                test->write);
                                break;
                        case SET_READ_TEST:
-                               REG_SET_AND_CHECK(test->reg + (i * test->reg_offset),
+                               REG_SET_AND_CHECK(test->reg +
+                                               (i * test->reg_offset),
                                                test->mask,
                                                test->write);
                                break;
@@ -1083,16 +1091,17 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
 {
        struct e1000_hw *hw = &adapter->hw;
        struct net_device *netdev = adapter->netdev;
-       u32 mask, i = 0, shared_int = true;
+       u32 mask, ics_mask, i = 0, shared_int = true;
        u32 irq = adapter->pdev->irq;
 
        *data = 0;
 
        /* Hook up test interrupt handler just for this test */
-       if (adapter->msix_entries) {
+       if (adapter->msix_entries)
                /* NOTE: we don't test MSI-X interrupts here, yet */
                return 0;
-       } else if (adapter->flags & IGB_FLAG_HAS_MSI) {
+
+       if (adapter->flags & IGB_FLAG_HAS_MSI) {
                shared_int = false;
                if (request_irq(irq, &igb_test_intr, 0, netdev->name, netdev)) {
                        *data = 1;
@@ -1108,16 +1117,31 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
        }
        dev_info(&adapter->pdev->dev, "testing %s interrupt\n",
                (shared_int ? "shared" : "unshared"));
-
        /* Disable all the interrupts */
        wr32(E1000_IMC, 0xFFFFFFFF);
        msleep(10);
 
+       /* Define all writable bits for ICS */
+       switch(hw->mac.type) {
+       case e1000_82575:
+               ics_mask = 0x37F47EDD;
+               break;
+       case e1000_82576:
+               ics_mask = 0x77D4FBFD;
+               break;
+       default:
+               ics_mask = 0x7FFFFFFF;
+               break;
+       }
+
        /* Test each interrupt */
-       for (; i < 10; i++) {
+       for (; i < 31; i++) {
                /* Interrupt to test */
                mask = 1 << i;
 
+               if (!(mask & ics_mask))
+                       continue;
+
                if (!shared_int) {
                        /* Disable the interrupt to be reported in
                         * the cause register and then force the same
@@ -1126,8 +1150,12 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
                         * test failed.
                         */
                        adapter->test_icr = 0;
-                       wr32(E1000_IMC, ~mask & 0x00007FFF);
-                       wr32(E1000_ICS, ~mask & 0x00007FFF);
+
+                       /* Flush any pending interrupts */
+                       wr32(E1000_ICR, ~0);
+
+                       wr32(E1000_IMC, mask);
+                       wr32(E1000_ICS, mask);
                        msleep(10);
 
                        if (adapter->test_icr & mask) {
@@ -1143,6 +1171,10 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
                 * test failed.
                 */
                adapter->test_icr = 0;
+
+               /* Flush any pending interrupts */
+               wr32(E1000_ICR, ~0);
+
                wr32(E1000_IMS, mask);
                wr32(E1000_ICS, mask);
                msleep(10);
@@ -1160,11 +1192,15 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
                         * test failed.
                         */
                        adapter->test_icr = 0;
-                       wr32(E1000_IMC, ~mask & 0x00007FFF);
-                       wr32(E1000_ICS, ~mask & 0x00007FFF);
+
+                       /* Flush any pending interrupts */
+                       wr32(E1000_ICR, ~0);
+
+                       wr32(E1000_IMC, ~mask);
+                       wr32(E1000_ICS, ~mask);
                        msleep(10);
 
-                       if (adapter->test_icr) {
+                       if (adapter->test_icr & mask) {
                                *data = 5;
                                break;
                        }
@@ -1172,7 +1208,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
        }
 
        /* Disable all the interrupts */
-       wr32(E1000_IMC, 0xFFFFFFFF);
+       wr32(E1000_IMC, ~0);
        msleep(10);
 
        /* Unhook test interrupt handler */
@@ -1236,6 +1272,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
        struct igb_ring *tx_ring = &adapter->test_tx_ring;
        struct igb_ring *rx_ring = &adapter->test_rx_ring;
        struct pci_dev *pdev = adapter->pdev;
+       struct igb_buffer *buffer_info;
        u32 rctl;
        int i, ret_val;
 
@@ -1252,7 +1289,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
                goto err_nomem;
        }
 
-       tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+       tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
        tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
                                             &tx_ring->dma);
@@ -1266,7 +1303,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
                        ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
        wr32(E1000_TDBAH(0), ((u64) tx_ring->dma >> 32));
        wr32(E1000_TDLEN(0),
-                       tx_ring->count * sizeof(struct e1000_tx_desc));
+                       tx_ring->count * sizeof(union e1000_adv_tx_desc));
        wr32(E1000_TDH(0), 0);
        wr32(E1000_TDT(0), 0);
        wr32(E1000_TCTL,
@@ -1275,27 +1312,31 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
                        E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
 
        for (i = 0; i < tx_ring->count; i++) {
-               struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+               union e1000_adv_tx_desc *tx_desc;
                struct sk_buff *skb;
                unsigned int size = 1024;
 
+               tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
                skb = alloc_skb(size, GFP_KERNEL);
                if (!skb) {
                        ret_val = 3;
                        goto err_nomem;
                }
                skb_put(skb, size);
-               tx_ring->buffer_info[i].skb = skb;
-               tx_ring->buffer_info[i].length = skb->len;
-               tx_ring->buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, skb->len,
-                                      PCI_DMA_TODEVICE);
-               tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
-               tx_desc->lower.data = cpu_to_le32(skb->len);
-               tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
-                                                  E1000_TXD_CMD_IFCS |
-                                                  E1000_TXD_CMD_RS);
-               tx_desc->upper.data = 0;
+               buffer_info = &tx_ring->buffer_info[i];
+               buffer_info->skb = skb;
+               buffer_info->length = skb->len;
+               buffer_info->dma = pci_map_single(pdev, skb->data, skb->len,
+                                                 PCI_DMA_TODEVICE);
+               tx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
+               tx_desc->read.olinfo_status = cpu_to_le32(skb->len) <<
+                                             E1000_ADVTXD_PAYLEN_SHIFT;
+               tx_desc->read.cmd_type_len = cpu_to_le32(skb->len);
+               tx_desc->read.cmd_type_len |= cpu_to_le32(E1000_TXD_CMD_EOP |
+                                                         E1000_TXD_CMD_IFCS |
+                                                         E1000_TXD_CMD_RS |
+                                                         E1000_ADVTXD_DTYP_DATA |
+                                                         E1000_ADVTXD_DCMD_DEXT);
        }
 
        /* Setup Rx descriptor ring and Rx buffers */
@@ -1311,7 +1352,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
                goto err_nomem;
        }
 
-       rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+       rx_ring->size = rx_ring->count * sizeof(union e1000_adv_rx_desc);
        rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
                                             &rx_ring->dma);
        if (!rx_ring->desc) {
@@ -1330,16 +1371,17 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
        wr32(E1000_RDH(0), 0);
        wr32(E1000_RDT(0), 0);
        rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
-       rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
-               E1000_RCTL_RDMTS_HALF |
+       rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_RDMTS_HALF |
                (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
        wr32(E1000_RCTL, rctl);
-       wr32(E1000_SRRCTL(0), 0);
+       wr32(E1000_SRRCTL(0), E1000_SRRCTL_DESCTYPE_ADV_ONEBUF);
 
        for (i = 0; i < rx_ring->count; i++) {
-               struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+               union e1000_adv_rx_desc *rx_desc;
                struct sk_buff *skb;
 
+               buffer_info = &rx_ring->buffer_info[i];
+               rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
                skb = alloc_skb(IGB_RXBUFFER_2048 + NET_IP_ALIGN,
                                GFP_KERNEL);
                if (!skb) {
@@ -1347,11 +1389,11 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
                        goto err_nomem;
                }
                skb_reserve(skb, NET_IP_ALIGN);
-               rx_ring->buffer_info[i].skb = skb;
-               rx_ring->buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, IGB_RXBUFFER_2048,
-                                      PCI_DMA_FROMDEVICE);
-               rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
+               buffer_info->skb = skb;
+               buffer_info->dma = pci_map_single(pdev, skb->data,
+                                                 IGB_RXBUFFER_2048,
+                                                 PCI_DMA_FROMDEVICE);
+               rx_desc->read.pkt_addr = cpu_to_le64(buffer_info->dma);
                memset(skb->data, 0x00, skb->len);
        }
 
@@ -1450,7 +1492,7 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)
                         E1000_CTRL_TFCE |
                         E1000_CTRL_LRST);
                reg |= E1000_CTRL_SLU |
-                      E1000_CTRL_FD; 
+                      E1000_CTRL_FD;
                wr32(E1000_CTRL, reg);
 
                /* Unset switch control to serdes energy detect */
@@ -1737,6 +1779,15 @@ static int igb_wol_exclusion(struct igb_adapter *adapter,
                /* return success for non excluded adapter ports */
                retval = 0;
                break;
+       case E1000_DEV_ID_82576_QUAD_COPPER:
+               /* quad port adapters only support WoL on port A */
+               if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) {
+                       wol->supported = 0;
+                       break;
+               }
+               /* return success for non excluded adapter ports */
+               retval = 0;
+               break;
        default:
                /* dual port cards only support WoL on port A from now on
                 * unless it was enabled in the eeprom for port B
@@ -1819,9 +1870,6 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        return 0;
 }
 
-/* toggle LED 4 times per second = 2 "blinks" per second */
-#define IGB_ID_INTERVAL                (HZ/4)
-
 /* bit defines for adapter->led_status */
 #define IGB_LED_ON             0