]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/tg3.c
[PATCH] fix wrong error code on interrupted close syscalls
[mv-sheeva.git] / drivers / net / tg3.c
index eafca2a0dd00e500f97303c4616b119df9260bf5..c25ba273b74596b9727d00d695b1083229efdf36 100644 (file)
@@ -68,8 +68,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.65"
-#define DRV_MODULE_RELDATE     "August 07, 2006"
+#define DRV_MODULE_VERSION     "3.66"
+#define DRV_MODULE_RELDATE     "September 23, 2006"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -199,6 +199,8 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
        {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)},
@@ -426,6 +428,16 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
                readl(mbox);
 }
 
+static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off)
+{
+       return (readl(tp->regs + off + GRCMBOX_BASE));
+}
+
+static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
+{
+       writel(val, tp->regs + off + GRCMBOX_BASE);
+}
+
 #define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val)
 #define tw32_mailbox_f(reg, val)       tw32_mailbox_flush(tp, (reg), (val))
 #define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val)
@@ -441,6 +453,10 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
 {
        unsigned long flags;
 
+       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+           (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
+               return;
+
        spin_lock_irqsave(&tp->indirect_lock, flags);
        if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
                pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
@@ -462,6 +478,12 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
 {
        unsigned long flags;
 
+       if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+           (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
+               *val = 0;
+               return;
+       }
+
        spin_lock_irqsave(&tp->indirect_lock, flags);
        if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
                pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
@@ -491,6 +513,9 @@ static inline void tg3_cond_int(struct tg3 *tp)
        if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
            (tp->hw_status->status & SD_STATUS_UPDATED))
                tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+       else
+               tw32(HOSTCC_MODE, tp->coalesce_mode |
+                    (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
 }
 
 static void tg3_enable_ints(struct tg3 *tp)
@@ -656,6 +681,10 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
        unsigned int loops;
        int ret;
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+           (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
+               return 0;
+
        if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
                tw32_f(MAC_MI_MODE,
                     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
@@ -1006,6 +1035,24 @@ out:
                                 phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               u32 phy_reg;
+
+               /* adjust output voltage */
+               tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12);
+
+               if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phy_reg)) {
+                       u32 phy_reg2;
+
+                       tg3_writephy(tp, MII_TG3_EPHY_TEST,
+                                    phy_reg | MII_TG3_EPHY_SHADOW_EN);
+                       /* Enable auto-MDIX */
+                       if (!tg3_readphy(tp, 0x10, &phy_reg2))
+                               tg3_writephy(tp, 0x10, phy_reg2 | 0x4000);
+                       tg3_writephy(tp, MII_TG3_EPHY_TEST, phy_reg);
+               }
+       }
+
        tg3_phy_set_wirespeed(tp);
        return 0;
 }
@@ -1122,8 +1169,11 @@ static void tg3_power_down_phy(struct tg3 *tp)
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                return;
 
-       tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF);
-       tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+               tg3_writephy(tp, MII_TG3_EXT_CTRL,
+                            MII_TG3_EXT_CTRL_FORCE_LED_OFF);
+               tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
+       }
 
        /* The PHY should not be powered down on some chips because
         * of bugs.
@@ -1207,7 +1257,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                tg3_setup_phy(tp, 0);
        }
 
-       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               u32 val;
+
+               val = tr32(GRC_VCPU_EXT_CTRL);
+               tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL);
+       } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
                int i;
                u32 val;
 
@@ -1471,6 +1526,13 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
                break;
 
        default:
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+                       *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
+                                SPEED_10;
+                       *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
+                                 DUPLEX_HALF;
+                       break;
+               }
                *speed = SPEED_INVALID;
                *duplex = DUPLEX_INVALID;
                break;
@@ -1753,7 +1815,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 
        if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
                tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
-       else
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
                tg3_writephy(tp, MII_TG3_IMASK, ~0);
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -3553,8 +3615,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
 
        if ((sblk->status & SD_STATUS_UPDATED) ||
            !(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
-               tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-                            0x00000001);
+               tg3_disable_ints(tp);
                return IRQ_RETVAL(1);
        }
        return IRQ_RETVAL(0);
@@ -4667,6 +4728,15 @@ static int tg3_poll_fw(struct tg3 *tp)
        int i;
        u32 val;
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               for (i = 0; i < 400; i++) {
+                       if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
+                               return 0;
+                       udelay(10);
+               }
+               return -ENODEV;
+       }
+
        /* Wait for firmware initialization to complete. */
        for (i = 0; i < 100000; i++) {
                tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
@@ -4735,6 +4805,12 @@ static int tg3_chip_reset(struct tg3 *tp)
                }
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
+               tw32(GRC_VCPU_EXT_CTRL,
+                    tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
+       }
+
        if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
                val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
        tw32(GRC_MISC_CFG, val);
@@ -5066,6 +5142,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
        BUG_ON(offset == TX_CPU_BASE &&
            (tp->tg3_flags2 & TG3_FLG2_5705_PLUS));
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               u32 val = tr32(GRC_VCPU_EXT_CTRL);
+
+               tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
+               return 0;
+       }
        if (offset == RX_CPU_BASE) {
                for (i = 0; i < 10000; i++) {
                        tw32(offset + CPU_STATE, 0xffffffff);
@@ -6070,6 +6152,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                val = 1;
        else if (val > tp->rx_std_max_post)
                val = tp->rx_std_max_post;
+       else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+                       tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
+
+               if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2))
+                       val = TG3_RX_INTERNAL_RING_SZ_5906 / 2;
+       }
 
        tw32(RCVBDI_STD_THRESH, val);
 
@@ -6490,7 +6579,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if (err)
                return err;
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
                u32 tmp;
 
                /* Clear CRC stats. */
@@ -6769,8 +6859,7 @@ static int tg3_request_irq(struct tg3 *tp)
 static int tg3_test_interrupt(struct tg3 *tp)
 {
        struct net_device *dev = tp->dev;
-       int err, i;
-       u32 int_mbox = 0;
+       int err, i, intr_ok = 0;
 
        if (!netif_running(dev))
                return -ENODEV;
@@ -6791,10 +6880,18 @@ static int tg3_test_interrupt(struct tg3 *tp)
               HOSTCC_MODE_NOW);
 
        for (i = 0; i < 5; i++) {
+               u32 int_mbox, misc_host_ctrl;
+
                int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 +
                                        TG3_64BIT_REG_LOW);
-               if (int_mbox != 0)
+               misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
+
+               if ((int_mbox != 0) ||
+                   (misc_host_ctrl & MISC_HOST_CTRL_MASK_PCI_INT)) {
+                       intr_ok = 1;
                        break;
+               }
+
                msleep(10);
        }
 
@@ -6807,7 +6904,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
        if (err)
                return err;
 
-       if (int_mbox != 0)
+       if (intr_ok)
                return 0;
 
        return -EIO;
@@ -6984,9 +7081,10 @@ static int tg3_open(struct net_device *dev)
 
                if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
                        if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) {
-                               u32 val = tr32(0x7c04);
+                               u32 val = tr32(PCIE_TRANSACTION_CFG);
 
-                               tw32(0x7c04, val | (1 << 29));
+                               tw32(PCIE_TRANSACTION_CFG,
+                                    val | PCIE_TRANS_CFG_1SHOT_MSI);
                        }
                }
        }
@@ -7941,7 +8039,8 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
                        return -EINVAL;
                return 0;
        }
-       if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) {
+       if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
+           (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
                if (value)
                        dev->features |= NETIF_F_TSO6;
                else
@@ -8195,6 +8294,8 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
 
 #define NVRAM_TEST_SIZE 0x100
 #define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
+#define NVRAM_SELFBOOT_HW_SIZE 0x20
+#define NVRAM_SELFBOOT_DATA_SIZE 0x1c
 
 static int tg3_test_nvram(struct tg3 *tp)
 {
@@ -8206,12 +8307,14 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        if (magic == TG3_EEPROM_MAGIC)
                size = NVRAM_TEST_SIZE;
-       else if ((magic & 0xff000000) == 0xa5000000) {
+       else if ((magic & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) {
                if ((magic & 0xe00000) == 0x200000)
                        size = NVRAM_SELFBOOT_FORMAT1_SIZE;
                else
                        return 0;
-       } else
+       } else if ((magic & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
+               size = NVRAM_SELFBOOT_HW_SIZE;
+       else
                return -EIO;
 
        buf = kmalloc(size, GFP_KERNEL);
@@ -8230,7 +8333,8 @@ static int tg3_test_nvram(struct tg3 *tp)
                goto out;
 
        /* Selfboot format */
-       if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) {
+       if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_FW_MSK) ==
+           TG3_EEPROM_MAGIC_FW) {
                u8 *buf8 = (u8 *) buf, csum8 = 0;
 
                for (i = 0; i < size; i++)
@@ -8245,6 +8349,51 @@ static int tg3_test_nvram(struct tg3 *tp)
                goto out;
        }
 
+       if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_HW_MSK) ==
+           TG3_EEPROM_MAGIC_HW) {
+               u8 data[NVRAM_SELFBOOT_DATA_SIZE];
+               u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
+               u8 *buf8 = (u8 *) buf;
+               int j, k;
+
+               /* Separate the parity bits and the data bytes.  */
+               for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
+                       if ((i == 0) || (i == 8)) {
+                               int l;
+                               u8 msk;
+
+                               for (l = 0, msk = 0x80; l < 7; l++, msk >>= 1)
+                                       parity[k++] = buf8[i] & msk;
+                               i++;
+                       }
+                       else if (i == 16) {
+                               int l;
+                               u8 msk;
+
+                               for (l = 0, msk = 0x20; l < 6; l++, msk >>= 1)
+                                       parity[k++] = buf8[i] & msk;
+                               i++;
+
+                               for (l = 0, msk = 0x80; l < 8; l++, msk >>= 1)
+                                       parity[k++] = buf8[i] & msk;
+                               i++;
+                       }
+                       data[j++] = buf8[i];
+               }
+
+               err = -EIO;
+               for (i = 0; i < NVRAM_SELFBOOT_DATA_SIZE; i++) {
+                       u8 hw8 = hweight8(data[i]);
+
+                       if ((hw8 & 0x1) && parity[i])
+                               goto out;
+                       else if (!(hw8 & 0x1) && !parity[i])
+                               goto out;
+               }
+               err = 0;
+               goto out;
+       }
+
        /* Bootstrap checksum at offset 0x10 */
        csum = calc_crc((unsigned char *) buf, 0x10);
        if(csum != cpu_to_le32(buf[0x10/4]))
@@ -8291,7 +8440,7 @@ static int tg3_test_link(struct tg3 *tp)
 /* Only test the commonly used registers */
 static int tg3_test_registers(struct tg3 *tp)
 {
-       int i, is_5705;
+       int i, is_5705, is_5750;
        u32 offset, read_mask, write_mask, val, save_val, read_val;
        static struct {
                u16 offset;
@@ -8299,6 +8448,7 @@ static int tg3_test_registers(struct tg3 *tp)
 #define TG3_FL_5705    0x1
 #define TG3_FL_NOT_5705        0x2
 #define TG3_FL_NOT_5788        0x4
+#define TG3_FL_NOT_5750        0x8
                u32 read_mask;
                u32 write_mask;
        } reg_tbl[] = {
@@ -8409,9 +8559,9 @@ static int tg3_test_registers(struct tg3 *tp)
                        0xffffffff, 0x00000000 },
 
                /* Buffer Manager Control Registers. */
-               { BUFMGR_MB_POOL_ADDR, 0x0000,
+               { BUFMGR_MB_POOL_ADDR, TG3_FL_NOT_5750,
                        0x00000000, 0x007fff80 },
-               { BUFMGR_MB_POOL_SIZE, 0x0000,
+               { BUFMGR_MB_POOL_SIZE, TG3_FL_NOT_5750,
                        0x00000000, 0x007fffff },
                { BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
                        0x00000000, 0x0000003f },
@@ -8437,10 +8587,12 @@ static int tg3_test_registers(struct tg3 *tp)
                { 0xffff, 0x0000, 0x00000000, 0x00000000 },
        };
 
-       if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+       is_5705 = is_5750 = 0;
+       if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
                is_5705 = 1;
-       else
-               is_5705 = 0;
+               if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
+                       is_5750 = 1;
+       }
 
        for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
                if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
@@ -8453,6 +8605,9 @@ static int tg3_test_registers(struct tg3 *tp)
                    (reg_tbl[i].flags & TG3_FL_NOT_5788))
                        continue;
 
+               if (is_5750 && (reg_tbl[i].flags & TG3_FL_NOT_5750))
+                       continue;
+
                offset = (u32) reg_tbl[i].offset;
                read_mask = reg_tbl[i].read_mask;
                write_mask = reg_tbl[i].write_mask;
@@ -8544,6 +8699,13 @@ static int tg3_test_memory(struct tg3 *tp)
                { 0x00008000, 0x02000},
                { 0x00010000, 0x0c000},
                { 0xffffffff, 0x00000}
+       }, mem_tbl_5906[] = {
+               { 0x00000200, 0x00008},
+               { 0x00004000, 0x00400},
+               { 0x00006000, 0x00400},
+               { 0x00008000, 0x01000},
+               { 0x00010000, 0x01000},
+               { 0xffffffff, 0x00000}
        };
        struct mem_entry *mem_tbl;
        int err = 0;
@@ -8553,6 +8715,8 @@ static int tg3_test_memory(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)
                        mem_tbl = mem_tbl_5755;
+               else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+                       mem_tbl = mem_tbl_5906;
                else
                        mem_tbl = mem_tbl_5705;
        } else
@@ -8598,6 +8762,21 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
        } else if (loopback_mode == TG3_PHY_LOOPBACK) {
                u32 val;
 
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+                       u32 phytest;
+
+                       if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phytest)) {
+                               u32 phy;
+
+                               tg3_writephy(tp, MII_TG3_EPHY_TEST,
+                                            phytest | MII_TG3_EPHY_SHADOW_EN);
+                               if (!tg3_readphy(tp, 0x1b, &phy))
+                                       tg3_writephy(tp, 0x1b, phy & ~0x20);
+                               if (!tg3_readphy(tp, 0x10, &phy))
+                                       tg3_writephy(tp, 0x10, phy & ~0x4000);
+                               tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest);
+                       }
+               }
                val = BMCR_LOOPBACK | BMCR_FULLDPLX;
                if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
                        val |= BMCR_SPEED100;
@@ -8606,6 +8785,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
 
                tg3_writephy(tp, MII_BMCR, val);
                udelay(40);
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+                       tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800);
+
                /* reset to prevent losing 1st rx packet intermittently */
                if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
                        tw32_f(MAC_RX_MODE, RX_MODE_RESET);
@@ -9019,7 +9201,9 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
        if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
                return;
 
-       if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000))
+       if ((magic != TG3_EEPROM_MAGIC) &&
+           ((magic & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW) &&
+           ((magic & TG3_EEPROM_MAGIC_HW_MSK) != TG3_EEPROM_MAGIC_HW))
                return;
 
        /*
@@ -9257,6 +9441,13 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
        }
 }
 
+static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
+{
+       tp->nvram_jedecnum = JEDEC_ATMEL;
+       tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+       tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+}
+
 /* Chips other than 5700/5701 use the NVRAM for fetching info. */
 static void __devinit tg3_nvram_init(struct tg3 *tp)
 {
@@ -9293,6 +9484,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
                        tg3_get_5755_nvram_info(tp);
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
                        tg3_get_5787_nvram_info(tp);
+               else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+                       tg3_get_5906_nvram_info(tp);
                else
                        tg3_get_nvram_info(tp);
 
@@ -9766,6 +9959,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
        /* Assume an onboard device by default.  */
        tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM))
+                       tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
+               return;
+       }
+
        tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
        if (val == NIC_SRAM_DATA_SIG_MAGIC) {
                u32 nic_cfg, led_cfg;
@@ -10097,7 +10296,10 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
        }
 
 out_not_found:
-       strcpy(tp->board_part_number, "none");
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+               strcpy(tp->board_part_number, "BCM95906");
+       else
+               strcpy(tp->board_part_number, "none");
 }
 
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
@@ -10299,6 +10501,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            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_5906 ||
            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
 
@@ -10308,7 +10511,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 
        if (tp->tg3_flags2 & TG3_FLG2_5750_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_5787 ||
+                   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;
                } else {
@@ -10325,7 +10529,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
            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_5787 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
                tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
        if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
@@ -10455,6 +10660,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                pci_cmd &= ~PCI_COMMAND_MEMORY;
                pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
        }
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+               tp->read32_mbox = tg3_read32_mbox_5906;
+               tp->write32_mbox = tg3_write32_mbox_5906;
+               tp->write32_tx_mbox = tg3_write32_mbox_5906;
+               tp->write32_rx_mbox = tg3_write32_mbox_5906;
+       }
 
        if (tp->write32 == tg3_write_indirect_reg32 ||
            ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
@@ -10526,6 +10737,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
             (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
             (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) ||
            (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
                tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
 
@@ -10539,7 +10751,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)
                        tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
-               else
+               else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
                        tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
        }
 
@@ -10629,7 +10841,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
              tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
            (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
             (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
-             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)))
+             tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)) ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
 
        err = tg3_phy_probe(tp);
@@ -10680,7 +10893,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
         * straddle the 4GB address boundary in some cases.
         */
        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_5787 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                tp->dev->hard_start_xmit = tg3_start_xmit;
        else
                tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
@@ -10761,6 +10975,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
                else
                        tg3_nvram_unlock(tp);
        }
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+               mac_offset = 0x10;
 
        /* First try to get it from MAC address mailbox. */
        tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
@@ -11244,6 +11460,12 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
                        DEFAULT_MB_MACRX_LOW_WATER_5705;
                tp->bufmgr_config.mbuf_high_water =
                        DEFAULT_MB_HIGH_WATER_5705;
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+                       tp->bufmgr_config.mbuf_mac_rx_low_water =
+                               DEFAULT_MB_MACRX_LOW_WATER_5906;
+                       tp->bufmgr_config.mbuf_high_water =
+                               DEFAULT_MB_HIGH_WATER_5906;
+               }
 
                tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
                        DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
@@ -11288,6 +11510,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM5755:    return "5755";
        case PHY_ID_BCM5787:    return "5787";
        case PHY_ID_BCM5756:    return "5722/5756";
+       case PHY_ID_BCM5906:    return "5906";
        case PHY_ID_BCM8002:    return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
@@ -11590,7 +11813,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
         */
        if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
                dev->features |= NETIF_F_TSO;
-               if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)
+               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;
        }