ip1000: menu location change
[safe/jmp/linux-2.6] / drivers / net / tg3.c
index 3200c9c..22eb7c8 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.82"
-#define DRV_MODULE_RELDATE     "October 5, 2007"
+#define DRV_MODULE_VERSION     "3.86"
+#define DRV_MODULE_RELDATE     "November 9, 2007"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -200,6 +200,9 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -314,6 +317,16 @@ static u32 tg3_read32(struct tg3 *tp, u32 off)
        return (readl(tp->regs + off));
 }
 
+static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
+{
+       writel(val, tp->aperegs + off);
+}
+
+static u32 tg3_ape_read32(struct tg3 *tp, u32 off)
+{
+       return (readl(tp->aperegs + off));
+}
+
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 {
        unsigned long flags;
@@ -500,6 +513,73 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
        spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
+static void tg3_ape_lock_init(struct tg3 *tp)
+{
+       int i;
+
+       /* Make sure the driver hasn't any stale locks. */
+       for (i = 0; i < 8; i++)
+               tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
+                               APE_LOCK_GRANT_DRIVER);
+}
+
+static int tg3_ape_lock(struct tg3 *tp, int locknum)
+{
+       int i, off;
+       int ret = 0;
+       u32 status;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               return 0;
+
+       switch (locknum) {
+               case TG3_APE_LOCK_MEM:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       off = 4 * locknum;
+
+       tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+
+       /* Wait for up to 1 millisecond to acquire lock. */
+       for (i = 0; i < 100; i++) {
+               status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+               if (status == APE_LOCK_GRANT_DRIVER)
+                       break;
+               udelay(10);
+       }
+
+       if (status != APE_LOCK_GRANT_DRIVER) {
+               /* Revoke the lock request. */
+               tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+                               APE_LOCK_GRANT_DRIVER);
+
+               ret = -EBUSY;
+       }
+
+       return ret;
+}
+
+static void tg3_ape_unlock(struct tg3 *tp, int locknum)
+{
+       int off;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               return;
+
+       switch (locknum) {
+               case TG3_APE_LOCK_MEM:
+                       break;
+               default:
+                       return;
+       }
+
+       off = 4 * locknum;
+       tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+}
+
 static void tg3_disable_ints(struct tg3 *tp)
 {
        tw32(TG3PCI_MISC_HOST_CTRL,
@@ -1026,6 +1106,24 @@ static int tg3_phy_reset(struct tg3 *tp)
        if (err)
                return err;
 
+       if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+               u32 val;
+
+               val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+               if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
+                   CPMU_LSPD_1000MB_MACCLK_12_5) {
+                       val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+                       udelay(40);
+                       tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+               }
+
+               /* Disable GPHY autopowerdown. */
+               tg3_writephy(tp, MII_TG3_MISC_SHDW,
+                            MII_TG3_MISC_SHDW_WREN |
+                            MII_TG3_MISC_SHDW_APD_SEL |
+                            MII_TG3_MISC_SHDW_APD_WKTM_84MS);
+       }
+
 out:
        if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
@@ -1217,6 +1315,8 @@ static void tg3_nvram_unlock(struct tg3 *);
 
 static void tg3_power_down_phy(struct tg3 *tp)
 {
+       u32 val;
+
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
                        u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
@@ -1231,8 +1331,6 @@ static void tg3_power_down_phy(struct tg3 *tp)
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
-               u32 val;
-
                tg3_bmcr_reset(tp);
                val = tr32(GRC_MISC_CFG);
                tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
@@ -1252,6 +1350,14 @@ static void tg3_power_down_phy(struct tg3 *tp)
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
             (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
                return;
+
+       if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+               val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+               val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+               val |= CPMU_LSPD_1000MB_MACCLK_12_5;
+               tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+       }
+
        tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
 }
 
@@ -1448,7 +1554,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
        }
 
        if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
-           !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+           !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+           !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
                tg3_power_down_phy(tp);
 
        tg3_frob_aux_power(tp);
@@ -3045,6 +3152,23 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
                err = tg3_setup_copper_phy(tp, force_reset);
        }
 
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+           tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) {
+               u32 val, scale;
+
+               val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK;
+               if (val == CPMU_CLCK_STAT_MAC_CLCK_62_5)
+                       scale = 65;
+               else if (val == CPMU_CLCK_STAT_MAC_CLCK_6_25)
+                       scale = 6;
+               else
+                       scale = 12;
+
+               val = tr32(GRC_MISC_CFG) & ~GRC_MISC_CFG_PRESCALAR_MASK;
+               val |= (scale << GRC_MISC_CFG_PRESCALAR_SHIFT);
+               tw32(GRC_MISC_CFG, val);
+       }
+
        if (tp->link_config.active_speed == SPEED_1000 &&
            tp->link_config.active_duplex == DUPLEX_HALF)
                tw32(MAC_TX_LENGTHS,
@@ -3475,12 +3599,9 @@ next_pkt_nopost:
        return received;
 }
 
-static int tg3_poll(struct napi_struct *napi, int budget)
+static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
 {
-       struct tg3 *tp = container_of(napi, struct tg3, napi);
-       struct net_device *netdev = tp->dev;
        struct tg3_hw_status *sblk = tp->hw_status;
-       int work_done = 0;
 
        /* handle link change and other phy events */
        if (!(tp->tg3_flags &
@@ -3498,11 +3619,8 @@ static int tg3_poll(struct napi_struct *napi, int budget)
        /* run TX completion thread */
        if (sblk->idx[0].tx_consumer != tp->tx_cons) {
                tg3_tx(tp);
-               if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
-                       netif_rx_complete(netdev, napi);
-                       schedule_work(&tp->reset_task);
-                       return 0;
-               }
+               if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+                       return work_done;
        }
 
        /* run RX thread, within the bounds set by NAPI.
@@ -3510,21 +3628,50 @@ static int tg3_poll(struct napi_struct *napi, int budget)
         * code synchronizes with tg3->napi.poll()
         */
        if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
-               work_done = tg3_rx(tp, budget);
+               work_done += tg3_rx(tp, budget - work_done);
 
-       if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
-               tp->last_tag = sblk->status_tag;
-               rmb();
-       } else
-               sblk->status &= ~SD_STATUS_UPDATED;
+       return work_done;
+}
+
+static int tg3_poll(struct napi_struct *napi, int budget)
+{
+       struct tg3 *tp = container_of(napi, struct tg3, napi);
+       int work_done = 0;
+       struct tg3_hw_status *sblk = tp->hw_status;
+
+       while (1) {
+               work_done = tg3_poll_work(tp, work_done, budget);
+
+               if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+                       goto tx_recovery;
+
+               if (unlikely(work_done >= budget))
+                       break;
+
+               if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+                       /* tp->last_tag is used in tg3_restart_ints() below
+                        * to tell the hw how much work has been processed,
+                        * so we must read it before checking for more work.
+                        */
+                       tp->last_tag = sblk->status_tag;
+                       rmb();
+               } else
+                       sblk->status &= ~SD_STATUS_UPDATED;
 
-       /* if no more work, tell net stack and NIC we're done */
-       if (!tg3_has_work(tp)) {
-               netif_rx_complete(netdev, napi);
-               tg3_restart_ints(tp);
+               if (likely(!tg3_has_work(tp))) {
+                       netif_rx_complete(tp->dev, napi);
+                       tg3_restart_ints(tp);
+                       break;
+               }
        }
 
        return work_done;
+
+tx_recovery:
+       /* work_done is guaranteed to be less than budget. */
+       netif_rx_complete(tp->dev, napi);
+       schedule_work(&tp->reset_task);
+       return work_done;
 }
 
 static void tg3_irq_quiesce(struct tg3 *tp)
@@ -4726,6 +4873,80 @@ static void tg3_disable_nvram_access(struct tg3 *tp)
        }
 }
 
+static void tg3_ape_send_event(struct tg3 *tp, u32 event)
+{
+       int i;
+       u32 apedata;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+       if (apedata != APE_SEG_SIG_MAGIC)
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+       if (apedata != APE_FW_STATUS_READY)
+               return;
+
+       /* Wait for up to 1 millisecond for APE to service previous event. */
+       for (i = 0; i < 10; i++) {
+               if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
+                       return;
+
+               apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+
+               if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+                       tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
+                                       event | APE_EVENT_STATUS_EVENT_PENDING);
+
+               tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+
+               if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+                       break;
+
+               udelay(100);
+       }
+
+       if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+               tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+}
+
+static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
+{
+       u32 event;
+       u32 apedata;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               return;
+
+       switch (kind) {
+               case RESET_KIND_INIT:
+                       tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
+                                       APE_HOST_SEG_SIG_MAGIC);
+                       tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
+                                       APE_HOST_SEG_LEN_MAGIC);
+                       apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
+                       tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
+                       tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
+                                       APE_HOST_DRIVER_ID_MAGIC);
+                       tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
+                                       APE_HOST_BEHAV_NO_PHYLOCK);
+
+                       event = APE_EVENT_STATUS_STATE_START;
+                       break;
+               case RESET_KIND_SHUTDOWN:
+                       event = APE_EVENT_STATUS_STATE_UNLOAD;
+                       break;
+               case RESET_KIND_SUSPEND:
+                       event = APE_EVENT_STATUS_STATE_SUSPEND;
+                       break;
+               default:
+                       return;
+       }
+
+       event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
+
+       tg3_ape_send_event(tp, event);
+}
+
 /* tp->lock is held. */
 static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
 {
@@ -4753,6 +4974,10 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
                        break;
                };
        }
+
+       if (kind == RESET_KIND_INIT ||
+           kind == RESET_KIND_SUSPEND)
+               tg3_ape_driver_state_change(tp, kind);
 }
 
 /* tp->lock is held. */
@@ -4774,6 +4999,9 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
                        break;
                };
        }
+
+       if (kind == RESET_KIND_SHUTDOWN)
+               tg3_ape_driver_state_change(tp, kind);
 }
 
 /* tp->lock is held. */
@@ -4844,10 +5072,7 @@ static int tg3_poll_fw(struct tg3 *tp)
 /* Save PCI command register before chip reset */
 static void tg3_save_pci_state(struct tg3 *tp)
 {
-       u32 val;
-
-       pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
-       tp->pci_cmd = val;
+       pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
 }
 
 /* Restore PCI state after chip reset */
@@ -4864,9 +5089,22 @@ static void tg3_restore_pci_state(struct tg3 *tp)
        if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
            (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
                val |= PCISTATE_RETRY_SAME_DMA;
+       /* Allow reads and writes to the APE register and memory space. */
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+               val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+                      PCISTATE_ALLOW_APE_SHMEM_WR;
        pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
-       pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+       pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
+
+       if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
+               pcie_set_readrq(tp->pdev, 4096);
+       else {
+               pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+                                     tp->pci_cacheline_sz);
+               pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+                                     tp->pci_lat_timer);
+       }
 
        /* Make sure PCI-X relaxed ordering bit is clear. */
        if (tp->pcix_cap) {
@@ -4924,7 +5162,8 @@ static int tg3_chip_reset(struct tg3 *tp)
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                tw32(GRC_FASTBOOT_PC, 0);
 
        /*
@@ -5092,7 +5331,8 @@ static int tg3_chip_reset(struct tg3 *tp)
 /* tp->lock is held. */
 static void tg3_stop_fw(struct tg3 *tp)
 {
-       if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+       if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+          !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
                u32 val;
                int i;
 
@@ -6149,10 +6389,26 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        tg3_write_sig_legacy(tp, RESET_KIND_INIT);
 
-       if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0) {
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+           tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) {
                val = tr32(TG3_CPMU_CTRL);
                val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
                tw32(TG3_CPMU_CTRL, val);
+
+               val = tr32(TG3_CPMU_LSPD_10MB_CLK);
+               val &= ~CPMU_LSPD_10MB_MACCLK_MASK;
+               val |= CPMU_LSPD_10MB_MACCLK_6_25;
+               tw32(TG3_CPMU_LSPD_10MB_CLK, val);
+
+               val = tr32(TG3_CPMU_LNK_AWARE_PWRMD);
+               val &= ~CPMU_LNK_AWARE_MACCLK_MASK;
+               val |= CPMU_LNK_AWARE_MACCLK_6_25;
+               tw32(TG3_CPMU_LNK_AWARE_PWRMD, val);
+
+               val = tr32(TG3_CPMU_HST_ACC);
+               val &= ~CPMU_HST_ACC_MACCLK_MASK;
+               val |= CPMU_HST_ACC_MACCLK_6_25;
+               tw32(TG3_CPMU_HST_ACC, val);
        }
 
        /* This works around an issue with Athlon chipsets on
@@ -6173,6 +6429,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(TG3PCI_PCISTATE, val);
        }
 
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+               /* Allow reads and writes to the
+                * APE register and memory space.
+                */
+               val = tr32(TG3PCI_PCISTATE);
+               val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+                      PCISTATE_ALLOW_APE_SHMEM_WR;
+               tw32(TG3PCI_PCISTATE, val);
+       }
+
        if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
                /* Enable some hw fixes.  */
                val = tr32(TG3PCI_MSI_DATA);
@@ -6189,7 +6455,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if (err)
                return err;
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
                /* This value is determined during the probe time DMA
                 * engine test, tg3_test_dma.
                 */
@@ -6595,7 +6862,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        /* Enable host coalescing bug fix */
        if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
-           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784))
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
                val |= (1 << 29);
 
        tw32_f(WDMAC_MODE, val);
@@ -6623,7 +6891,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
                tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
-       tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+               tw32(SNDDATAC_MODE,
+                    SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
+       else
+               tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
        tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
        tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
        tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
@@ -6650,7 +6924,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        udelay(100);
 
        tp->rx_mode = RX_MODE_ENABLE;
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
 
        tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -6780,6 +7055,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                break;
        };
 
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+               /* Write our heartbeat update interval to APE. */
+               tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
+                               APE_HOST_HEARTBEAT_INT_DISABLE);
+
        tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
 
        return 0;
@@ -7147,10 +7427,6 @@ static int tg3_open(struct net_device *dev)
                } else if (pci_enable_msi(tp->pdev) == 0) {
                        u32 msi_mode;
 
-                       /* Hardware bug - MSI won't work if INTX disabled. */
-                       if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
-                               pci_intx(tp->pdev, 1);
-
                        msi_mode = tr32(MSGINT_MODE);
                        tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
                        tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
@@ -7913,6 +8189,7 @@ static int tg3_get_eeprom_len(struct net_device *dev)
 }
 
 static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
+static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val);
 static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val);
 
 static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
@@ -7920,7 +8197,8 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        struct tg3 *tp = netdev_priv(dev);
        int ret;
        u8  *pd;
-       u32 i, offset, len, val, b_offset, b_count;
+       u32 i, offset, len, b_offset, b_count;
+       __le32 val;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -7939,10 +8217,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        /* i.e. offset=1 len=2 */
                        b_count = len;
                }
-               ret = tg3_nvram_read(tp, offset-b_offset, &val);
+               ret = tg3_nvram_read_le(tp, offset-b_offset, &val);
                if (ret)
                        return ret;
-               val = cpu_to_le32(val);
                memcpy(data, ((char*)&val) + b_offset, b_count);
                len -= b_count;
                offset += b_count;
@@ -7952,12 +8229,11 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        /* read bytes upto the last 4 byte boundary */
        pd = &data[eeprom->len];
        for (i = 0; i < (len - (len & 3)); i += 4) {
-               ret = tg3_nvram_read(tp, offset + i, &val);
+               ret = tg3_nvram_read_le(tp, offset + i, &val);
                if (ret) {
                        eeprom->len += i;
                        return ret;
                }
-               val = cpu_to_le32(val);
                memcpy(pd + i, &val, 4);
        }
        eeprom->len += i;
@@ -7967,11 +8243,10 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                pd = &data[eeprom->len];
                b_count = len & 3;
                b_offset = offset + len - b_count;
-               ret = tg3_nvram_read(tp, b_offset, &val);
+               ret = tg3_nvram_read_le(tp, b_offset, &val);
                if (ret)
                        return ret;
-               val = cpu_to_le32(val);
-               memcpy(pd, ((char*)&val), b_count);
+               memcpy(pd, &val, b_count);
                eeprom->len += b_count;
        }
        return 0;
@@ -7983,8 +8258,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 {
        struct tg3 *tp = netdev_priv(dev);
        int ret;
-       u32 offset, len, b_offset, odd_len, start, end;
+       u32 offset, len, b_offset, odd_len;
        u8 *buf;
+       __le32 start, end;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -7997,10 +8273,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        if ((b_offset = (offset & 3))) {
                /* adjustments to start on required 4 byte boundary */
-               ret = tg3_nvram_read(tp, offset-b_offset, &start);
+               ret = tg3_nvram_read_le(tp, offset-b_offset, &start);
                if (ret)
                        return ret;
-               start = cpu_to_le32(start);
                len += b_offset;
                offset &= ~3;
                if (len < 4)
@@ -8012,10 +8287,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                /* adjustments to end on required 4 byte boundary */
                odd_len = 1;
                len = (len + 3) & ~3;
-               ret = tg3_nvram_read(tp, offset+len-4, &end);
+               ret = tg3_nvram_read_le(tp, offset+len-4, &end);
                if (ret)
                        return ret;
-               end = cpu_to_le32(end);
        }
 
        buf = data;
@@ -8053,7 +8327,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                                  SUPPORTED_100baseT_Full |
                                  SUPPORTED_10baseT_Half |
                                  SUPPORTED_10baseT_Full |
-                                 SUPPORTED_MII);
+                                 SUPPORTED_TP);
                cmd->port = PORT_TP;
        } else {
                cmd->supported |= SUPPORTED_FIBRE;
@@ -8190,10 +8464,12 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
        }
        if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
            (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
-               if (value)
+               if (value) {
                        dev->features |= NETIF_F_TSO6;
-               else
-                       dev->features &= ~NETIF_F_TSO6;
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                               dev->features |= NETIF_F_TSO_ECN;
+               } else
+                       dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
        }
        return ethtool_op_set_tso(dev, value);
 }
@@ -8372,7 +8648,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                ethtool_op_set_tx_ipv6_csum(dev, data);
        else
                ethtool_op_set_tx_csum(dev, data);
@@ -8447,13 +8724,16 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
 }
 
 #define NVRAM_TEST_SIZE 0x100
-#define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
+#define NVRAM_SELFBOOT_FORMAT1_0_SIZE  0x14
+#define NVRAM_SELFBOOT_FORMAT1_2_SIZE  0x18
+#define NVRAM_SELFBOOT_FORMAT1_3_SIZE  0x1c
 #define NVRAM_SELFBOOT_HW_SIZE 0x20
 #define NVRAM_SELFBOOT_DATA_SIZE 0x1c
 
 static int tg3_test_nvram(struct tg3 *tp)
 {
-       u32 *buf, csum, magic;
+       u32 csum, magic;
+       __le32 *buf;
        int i, j, k, err = 0, size;
 
        if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
@@ -8462,9 +8742,22 @@ static int tg3_test_nvram(struct tg3 *tp)
        if (magic == TG3_EEPROM_MAGIC)
                size = NVRAM_TEST_SIZE;
        else if ((magic & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) {
-               if ((magic & 0xe00000) == 0x200000)
-                       size = NVRAM_SELFBOOT_FORMAT1_SIZE;
-               else
+               if ((magic & TG3_EEPROM_SB_FORMAT_MASK) ==
+                   TG3_EEPROM_SB_FORMAT_1) {
+                       switch (magic & TG3_EEPROM_SB_REVISION_MASK) {
+                       case TG3_EEPROM_SB_REVISION_0:
+                               size = NVRAM_SELFBOOT_FORMAT1_0_SIZE;
+                               break;
+                       case TG3_EEPROM_SB_REVISION_2:
+                               size = NVRAM_SELFBOOT_FORMAT1_2_SIZE;
+                               break;
+                       case TG3_EEPROM_SB_REVISION_3:
+                               size = NVRAM_SELFBOOT_FORMAT1_3_SIZE;
+                               break;
+                       default:
+                               return 0;
+                       }
+               } else
                        return 0;
        } else if ((magic & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
                size = NVRAM_SELFBOOT_HW_SIZE;
@@ -8477,22 +8770,29 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        err = -EIO;
        for (i = 0, j = 0; i < size; i += 4, j++) {
-               u32 val;
-
-               if ((err = tg3_nvram_read(tp, i, &val)) != 0)
+               if ((err = tg3_nvram_read_le(tp, i, &buf[j])) != 0)
                        break;
-               buf[j] = cpu_to_le32(val);
        }
        if (i < size)
                goto out;
 
        /* Selfboot format */
-       if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_FW_MSK) ==
+       magic = swab32(le32_to_cpu(buf[0]));
+       if ((magic & TG3_EEPROM_MAGIC_FW_MSK) ==
            TG3_EEPROM_MAGIC_FW) {
                u8 *buf8 = (u8 *) buf, csum8 = 0;
 
-               for (i = 0; i < size; i++)
-                       csum8 += buf8[i];
+               if ((magic & TG3_EEPROM_SB_REVISION_MASK) ==
+                   TG3_EEPROM_SB_REVISION_2) {
+                       /* For rev 2, the csum doesn't include the MBA. */
+                       for (i = 0; i < TG3_EEPROM_SB_F1R2_MBA_OFF; i++)
+                               csum8 += buf8[i];
+                       for (i = TG3_EEPROM_SB_F1R2_MBA_OFF + 4; i < size; i++)
+                               csum8 += buf8[i];
+               } else {
+                       for (i = 0; i < size; i++)
+                               csum8 += buf8[i];
+               }
 
                if (csum8 == 0) {
                        err = 0;
@@ -8503,7 +8803,7 @@ static int tg3_test_nvram(struct tg3 *tp)
                goto out;
        }
 
-       if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_HW_MSK) ==
+       if ((magic & TG3_EEPROM_MAGIC_HW_MSK) ==
            TG3_EEPROM_MAGIC_HW) {
                u8 data[NVRAM_SELFBOOT_DATA_SIZE];
                u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
@@ -8549,12 +8849,12 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        /* Bootstrap checksum at offset 0x10 */
        csum = calc_crc((unsigned char *) buf, 0x10);
-       if(csum != cpu_to_le32(buf[0x10/4]))
+       if(csum != le32_to_cpu(buf[0x10/4]))
                goto out;
 
        /* Manufacturing block starts at offset 0x74, checksum at 0xfc */
        csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
-       if (csum != cpu_to_le32(buf[0xfc/4]))
+       if (csum != le32_to_cpu(buf[0xfc/4]))
                 goto out;
 
        err = 0;
@@ -8817,7 +9117,7 @@ static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
        int i;
        u32 j;
 
-       for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
+       for (i = 0; i < ARRAY_SIZE(test_pattern); i++) {
                for (j = 0; j < len; j += 4) {
                        u32 val;
 
@@ -8869,7 +9169,8 @@ static int tg3_test_memory(struct tg3 *tp)
        if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                        mem_tbl = mem_tbl_5755;
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                        mem_tbl = mem_tbl_5906;
@@ -9066,6 +9367,7 @@ out:
 static int tg3_test_loopback(struct tg3 *tp)
 {
        int err = 0;
+       u32 cpmuctrl = 0;
 
        if (!netif_running(tp->dev))
                return TG3_LOOPBACK_FAILED;
@@ -9074,8 +9376,40 @@ static int tg3_test_loopback(struct tg3 *tp)
        if (err)
                return TG3_LOOPBACK_FAILED;
 
+       if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+               int i;
+               u32 status;
+
+               tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER);
+
+               /* Wait for up to 40 microseconds to acquire lock. */
+               for (i = 0; i < 4; i++) {
+                       status = tr32(TG3_CPMU_MUTEX_GNT);
+                       if (status == CPMU_MUTEX_GNT_DRIVER)
+                               break;
+                       udelay(10);
+               }
+
+               if (status != CPMU_MUTEX_GNT_DRIVER)
+                       return TG3_LOOPBACK_FAILED;
+
+               /* Turn off power management based on link speed. */
+               cpmuctrl = tr32(TG3_CPMU_CTRL);
+               tw32(TG3_CPMU_CTRL,
+                    cpmuctrl & ~(CPMU_CTRL_LINK_SPEED_MODE |
+                                 CPMU_CTRL_LINK_AWARE_MODE));
+       }
+
        if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
                err |= TG3_MAC_LOOPBACK_FAILED;
+
+       if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+               tw32(TG3_CPMU_CTRL, cpmuctrl);
+
+               /* Release the mutex */
+               tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
+       }
+
        if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
                if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
                        err |= TG3_PHY_LOOPBACK_FAILED;
@@ -9834,6 +10168,15 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
        return ret;
 }
 
+static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val)
+{
+       u32 v;
+       int res = tg3_nvram_read(tp, offset, &v);
+       if (!res)
+               *val = cpu_to_le32(v);
+       return res;
+}
+
 static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val)
 {
        int err;
@@ -9851,13 +10194,14 @@ static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
        u32 val;
 
        for (i = 0; i < len; i += 4) {
-               u32 addr, data;
+               u32 addr;
+               __le32 data;
 
                addr = offset + i;
 
                memcpy(&data, buf + i, 4);
 
-               tw32(GRC_EEPROM_DATA, cpu_to_le32(data));
+               tw32(GRC_EEPROM_DATA, le32_to_cpu(data));
 
                val = tr32(GRC_EEPROM_ADDR);
                tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
@@ -9907,8 +10251,8 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                phy_addr = offset & ~pagemask;
 
                for (j = 0; j < pagesize; j += 4) {
-                       if ((ret = tg3_nvram_read(tp, phy_addr + j,
-                                               (u32 *) (tmp + j))))
+                       if ((ret = tg3_nvram_read_le(tp, phy_addr + j,
+                                               (__le32 *) (tmp + j))))
                                break;
                }
                if (ret)
@@ -9952,10 +10296,11 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                        break;
 
                for (j = 0; j < pagesize; j += 4) {
-                       u32 data;
+                       __be32 data;
 
-                       data = *((u32 *) (tmp + j));
-                       tw32(NVRAM_WRDATA, cpu_to_be32(data));
+                       data = *((__be32 *) (tmp + j));
+                       /* swab32(le32_to_cpu(data)), actually */
+                       tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
                        tw32(NVRAM_ADDR, phy_addr + j);
 
@@ -9989,10 +10334,11 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
        int i, ret = 0;
 
        for (i = 0; i < len; i += 4, offset += 4) {
-               u32 data, page_off, phy_addr, nvram_cmd;
+               u32 page_off, phy_addr, nvram_cmd;
+               __be32 data;
 
                memcpy(&data, buf + i, 4);
-               tw32(NVRAM_WRDATA, cpu_to_be32(data));
+               tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
                page_off = offset % tp->nvram_pagesize;
 
@@ -10014,6 +10360,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
                    (tp->nvram_jedecnum == JEDEC_ST) &&
                    (nvram_cmd & NVRAM_CMD_FIRST)) {
 
@@ -10184,8 +10531,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                        tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
                        tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
                }
-               if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC)
+               val = tr32(VCPU_CFGSHDW);
+               if (val & VCPU_CFGSHDW_ASPM_DBNC)
                        tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+               if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
+                   (val & VCPU_CFGSHDW_WOL_MAGPKT))
+                       tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
                return;
        }
 
@@ -10285,6 +10636,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                    tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
                        tp->led_ctrl = LED_CTRL_MODE_PHY_2;
 
+               if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+                   tp->pci_chip_rev_id == CHIPREV_ID_5784_A1)
+                       tp->led_ctrl = LED_CTRL_MODE_MAC;
+
                if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
                        tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
                        if ((tp->pdev->subsystem_vendor ==
@@ -10302,10 +10657,16 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                        if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
                                tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
                }
+               if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE)
+                       tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
                if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
                    !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
                        tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
+               if (tp->tg3_flags & TG3_FLAG_WOL_CAP &&
+                   nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)
+                       tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+
                if (cfg2 & (1 << 17))
                        tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
 
@@ -10334,7 +10695,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
         * firwmare access to the PHY hardware.
         */
        err = 0;
-       if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+       if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+           (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
                hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
        } else {
                /* Now read the physical PHY_ID from the chip and verify
@@ -10381,6 +10743,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
        }
 
        if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
+           !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
            !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
                u32 bmsr, adv_reg, tg3_ctrl, mask;
 
@@ -10477,6 +10840,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
                vpd_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_VPD);
                for (i = 0; i < 256; i += 4) {
                        u32 tmp, j = 0;
+                       __le32 v;
                        u16 tmp16;
 
                        pci_write_config_word(tp->pdev, vpd_cap + PCI_VPD_ADDR,
@@ -10493,8 +10857,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
 
                        pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA,
                                              &tmp);
-                       tmp = cpu_to_le32(tmp);
-                       memcpy(&vpd_data[i], &tmp, 4);
+                       v = cpu_to_le32(tmp);
+                       memcpy(&vpd_data[i], &v, 4);
                }
        }
 
@@ -10550,9 +10914,24 @@ out_not_found:
                strcpy(tp->board_part_number, "none");
 }
 
+static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
+{
+       u32 val;
+
+       if (tg3_nvram_read_swab(tp, offset, &val) ||
+           (val & 0xfc000000) != 0x0c000000 ||
+           tg3_nvram_read_swab(tp, offset + 4, &val) ||
+           val != 0)
+               return 0;
+
+       return 1;
+}
+
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
        u32 val, offset, start;
+       u32 ver_offset;
+       int i, bcnt;
 
        if (tg3_nvram_read_swab(tp, 0, &val))
                return;
@@ -10565,29 +10944,71 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
                return;
 
        offset = tg3_nvram_logical_addr(tp, offset);
-       if (tg3_nvram_read_swab(tp, offset, &val))
+
+       if (!tg3_fw_img_is_valid(tp, offset) ||
+           tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
                return;
 
-       if ((val & 0xfc000000) == 0x0c000000) {
-               u32 ver_offset, addr;
-               int i;
+       offset = offset + ver_offset - start;
+       for (i = 0; i < 16; i += 4) {
+               __le32 v;
+               if (tg3_nvram_read_le(tp, offset + i, &v))
+                       return;
+
+               memcpy(tp->fw_ver + i, &v, 4);
+       }
+
+       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               return;
 
-               if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
-                   tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
+       for (offset = TG3_NVM_DIR_START;
+            offset < TG3_NVM_DIR_END;
+            offset += TG3_NVM_DIRENT_SIZE) {
+               if (tg3_nvram_read_swab(tp, offset, &val))
                        return;
 
-               if (val != 0)
+               if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
+                       break;
+       }
+
+       if (offset == TG3_NVM_DIR_END)
+               return;
+
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+               start = 0x08000000;
+       else if (tg3_nvram_read_swab(tp, offset - 4, &start))
+               return;
+
+       if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
+           !tg3_fw_img_is_valid(tp, offset) ||
+           tg3_nvram_read_swab(tp, offset + 8, &val))
+               return;
+
+       offset += val - start;
+
+       bcnt = strlen(tp->fw_ver);
+
+       tp->fw_ver[bcnt++] = ',';
+       tp->fw_ver[bcnt++] = ' ';
+
+       for (i = 0; i < 4; i++) {
+               __le32 v;
+               if (tg3_nvram_read_le(tp, offset, &v))
                        return;
 
-               addr = offset + ver_offset - start;
-               for (i = 0; i < 16; i += 4) {
-                       if (tg3_nvram_read(tp, addr + i, &val))
-                               return;
+               offset += sizeof(v);
 
-                       val = cpu_to_le32(val);
-                       memcpy(tp->fw_ver + i, &val, 4);
+               if (bcnt > TG3_VER_SIZE - sizeof(v)) {
+                       memcpy(&tp->fw_ver[bcnt], &v, TG3_VER_SIZE - bcnt);
+                       break;
                }
+
+               memcpy(&tp->fw_ver[bcnt], &v, sizeof(v));
+               bcnt += sizeof(v);
        }
+
+       tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
 
 static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
@@ -10759,6 +11180,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -10779,6 +11201,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
                        tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
                        tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -10797,12 +11220,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
                tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
        pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
        if (pcie_cap != 0) {
                tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+
+               pcie_set_readrq(tp->pdev, 4096);
+
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
                        u16 lnkctl;
 
@@ -10972,9 +11399,27 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
         */
        tg3_get_eeprom_hw_cfg(tp);
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+               /* Allow reads and writes to the
+                * APE register and memory space.
+                */
+               pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+                                PCISTATE_ALLOW_APE_SHMEM_WR;
+               pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
+                                      pci_state_reg);
+       }
+
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
                tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
 
+               if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+                   tp->pci_chip_rev_id == CHIPREV_ID_5784_A1 ||
+                   tp->pci_chip_rev_id == CHIPREV_ID_5761_A0 ||
+                   tp->pci_chip_rev_id == CHIPREV_ID_5761_A1)
+                       tp->tg3_flags3 |= TG3_FLG3_5761_5784_AX_FIXES;
+       }
+
        /* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
         * GPIO1 driven high will bring 5700's external PHY out of reset.
         * It is also used as eeprom write protect on LOMs.
@@ -11042,7 +11487,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) {
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
                        if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
                            tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
                                tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
@@ -11186,6 +11632,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                tp->dev->hard_start_xmit = tg3_start_xmit;
        else
@@ -11206,11 +11653,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
                tp->rx_std_max_post = 8;
 
-       /* By default, disable wake-on-lan.  User can change this
-        * using ETHTOOL_SWOL.
-        */
-       tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
-
        if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
                tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
                                     PCIE_PWR_MGMT_L1_THRESH_MSK;
@@ -11810,6 +12252,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM5784:    return "5784";
        case PHY_ID_BCM5756:    return "5722/5756";
        case PHY_ID_BCM5906:    return "5906";
+       case PHY_ID_BCM5761:    return "5761";
        case PHY_ID_BCM8002:    return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
@@ -12112,6 +12555,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
                        dev->features |= NETIF_F_TSO6;
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                       dev->features |= NETIF_F_TSO_ECN;
        }
 
 
@@ -12129,6 +12574,28 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                goto err_out_iounmap;
        }
 
+       if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+               if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+                       printk(KERN_ERR PFX "Cannot find proper PCI device "
+                              "base address for APE, aborting.\n");
+                       err = -ENODEV;
+                       goto err_out_iounmap;
+               }
+
+               tg3reg_base = pci_resource_start(pdev, 2);
+               tg3reg_len = pci_resource_len(pdev, 2);
+
+               tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
+               if (tp->aperegs == 0UL) {
+                       printk(KERN_ERR PFX "Cannot map APE registers, "
+                              "aborting.\n");
+                       err = -ENOMEM;
+                       goto err_out_iounmap;
+               }
+
+               tg3_ape_lock_init(tp);
+       }
+
        /*
         * Reset chip in case UNDI or EFI driver did not shutdown
         * DMA self test will enable WDMAC and we'll see (spurious)
@@ -12143,7 +12610,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        err = tg3_test_dma(tp);
        if (err) {
                printk(KERN_ERR PFX "DMA engine test failed, aborting.\n");
-               goto err_out_iounmap;
+               goto err_out_apeunmap;
        }
 
        /* Tigon3 can do ipv4 only... and some chips have buggy
@@ -12153,7 +12620,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                        dev->features |= NETIF_F_IPV6_CSUM;
 
                tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -12171,7 +12639,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        if (err) {
                printk(KERN_ERR PFX "Cannot register net device, "
                       "aborting.\n");
-               goto err_out_iounmap;
+               goto err_out_apeunmap;
        }
 
        printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
@@ -12204,6 +12672,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        return 0;
 
+err_out_apeunmap:
+       if (tp->aperegs) {
+               iounmap(tp->aperegs);
+               tp->aperegs = NULL;
+       }
+
 err_out_iounmap:
        if (tp->regs) {
                iounmap(tp->regs);
@@ -12231,6 +12705,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
 
                flush_scheduled_work();
                unregister_netdev(dev);
+               if (tp->aperegs) {
+                       iounmap(tp->aperegs);
+                       tp->aperegs = NULL;
+               }
                if (tp->regs) {
                        iounmap(tp->regs);
                        tp->regs = NULL;
@@ -12309,11 +12787,6 @@ static int tg3_resume(struct pci_dev *pdev)
        if (err)
                return err;
 
-       /* Hardware bug - MSI won't work if INTX disabled. */
-       if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
-           (tp->tg3_flags2 & TG3_FLG2_USING_MSI))
-               pci_intx(tp->pdev, 1);
-
        netif_device_attach(dev);
 
        tg3_full_lock(tp, 0);