tg3: Download 57766 EEE service patch firmware
authorNithin Sujir <nsujir@broadcom.com>
Wed, 6 Mar 2013 17:02:34 +0000 (17:02 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 7 Mar 2013 20:31:32 +0000 (15:31 -0500)
This patch downloads the EEE service patch firmware and enables the necessary
EEE flags.

Reviewed-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h

index 54f604bbaeac1afc5d935d9cfc2dfb254ca17125..2b2bee61ddd75864083ddd72710b0ab7932a2492 100644 (file)
@@ -212,6 +212,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 #define TG3_FW_UPDATE_FREQ_SEC         (TG3_FW_UPDATE_TIMEOUT_SEC / 2)
 
 #define FIRMWARE_TG3           "tigon/tg3.bin"
+#define FIRMWARE_TG357766      "tigon/tg357766.bin"
 #define FIRMWARE_TG3TSO                "tigon/tg3_tso.bin"
 #define FIRMWARE_TG3TSO5       "tigon/tg3_tso5.bin"
 
@@ -3568,7 +3569,7 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
                                 u32 cpu_scratch_base, int cpu_scratch_size,
                                 const struct tg3_firmware_hdr *fw_hdr)
 {
-       int err, lock_err, i;
+       int err, i;
        void (*write_op)(struct tg3 *, u32, u32);
        int total_len = tp->fw->size;
 
@@ -3579,25 +3580,34 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
                return -EINVAL;
        }
 
-       if (tg3_flag(tp, 5705_PLUS))
+       if (tg3_flag(tp, 5705_PLUS) && tg3_asic_rev(tp) != ASIC_REV_57766)
                write_op = tg3_write_mem;
        else
                write_op = tg3_write_indirect_reg32;
 
-       /* It is possible that bootcode is still loading at this point.
-        * Get the nvram lock first before halting the cpu.
-        */
-       lock_err = tg3_nvram_lock(tp);
-       err = tg3_halt_cpu(tp, cpu_base);
-       if (!lock_err)
-               tg3_nvram_unlock(tp);
-       if (err)
-               goto out;
+       if (tg3_asic_rev(tp) != ASIC_REV_57766) {
+               /* It is possible that bootcode is still loading at this point.
+                * Get the nvram lock first before halting the cpu.
+                */
+               int lock_err = tg3_nvram_lock(tp);
+               err = tg3_halt_cpu(tp, cpu_base);
+               if (!lock_err)
+                       tg3_nvram_unlock(tp);
+               if (err)
+                       goto out;
 
-       for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
-               write_op(tp, cpu_scratch_base + i, 0);
-       tw32(cpu_base + CPU_STATE, 0xffffffff);
-       tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
+               for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
+                       write_op(tp, cpu_scratch_base + i, 0);
+               tw32(cpu_base + CPU_STATE, 0xffffffff);
+               tw32(cpu_base + CPU_MODE,
+                    tr32(cpu_base + CPU_MODE) | CPU_MODE_HALT);
+       } else {
+               /* Subtract additional main header for fragmented firmware and
+                * advance to the first fragment
+                */
+               total_len -= TG3_FW_HDR_LEN;
+               fw_hdr++;
+       }
 
        do {
                u32 *fw_data = (u32 *)(fw_hdr + 1);
@@ -3683,6 +3693,78 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
        return 0;
 }
 
+static int tg3_validate_rxcpu_state(struct tg3 *tp)
+{
+       const int iters = 1000;
+       int i;
+       u32 val;
+
+       /* Wait for boot code to complete initialization and enter service
+        * loop. It is then safe to download service patches
+        */
+       for (i = 0; i < iters; i++) {
+               if (tr32(RX_CPU_HWBKPT) == TG3_SBROM_IN_SERVICE_LOOP)
+                       break;
+
+               udelay(10);
+       }
+
+       if (i == iters) {
+               netdev_err(tp->dev, "Boot code not ready for service patches\n");
+               return -EBUSY;
+       }
+
+       val = tg3_read_indirect_reg32(tp, TG3_57766_FW_HANDSHAKE);
+       if (val & 0xff) {
+               netdev_warn(tp->dev,
+                           "Other patches exist. Not downloading EEE patch\n");
+               return -EEXIST;
+       }
+
+       return 0;
+}
+
+/* tp->lock is held. */
+static void tg3_load_57766_firmware(struct tg3 *tp)
+{
+       struct tg3_firmware_hdr *fw_hdr;
+
+       if (!tg3_flag(tp, NO_NVRAM))
+               return;
+
+       if (tg3_validate_rxcpu_state(tp))
+               return;
+
+       if (!tp->fw)
+               return;
+
+       /* This firmware blob has a different format than older firmware
+        * releases as given below. The main difference is we have fragmented
+        * data to be written to non-contiguous locations.
+        *
+        * In the beginning we have a firmware header identical to other
+        * firmware which consists of version, base addr and length. The length
+        * here is unused and set to 0xffffffff.
+        *
+        * This is followed by a series of firmware fragments which are
+        * individually identical to previous firmware. i.e. they have the
+        * firmware header and followed by data for that fragment. The version
+        * field of the individual fragment header is unused.
+        */
+
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
+       if (be32_to_cpu(fw_hdr->base_addr) != TG3_57766_FW_BASE_ADDR)
+               return;
+
+       if (tg3_rxcpu_pause(tp))
+               return;
+
+       /* tg3_load_firmware_cpu() will always succeed for the 57766 */
+       tg3_load_firmware_cpu(tp, 0, TG3_57766_FW_BASE_ADDR, 0, fw_hdr);
+
+       tg3_rxcpu_resume(tp);
+}
+
 /* tp->lock is held. */
 static int tg3_load_tso_firmware(struct tg3 *tp)
 {
@@ -9836,6 +9918,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                        return err;
        }
 
+       if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+               /* Ignore any errors for the firmware download. If download
+                * fails, the device will operate with EEE disabled
+                */
+               tg3_load_57766_firmware(tp);
+       }
+
        if (tg3_flag(tp, TSO_CAPABLE)) {
                err = tg3_load_tso_firmware(tp);
                if (err)
@@ -10940,7 +11029,15 @@ static int tg3_open(struct net_device *dev)
 
        if (tp->fw_needed) {
                err = tg3_request_firmware(tp);
-               if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
+               if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+                       if (err) {
+                               netdev_warn(tp->dev, "EEE capability disabled\n");
+                               tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
+                       } else if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+                               netdev_warn(tp->dev, "EEE capability restored\n");
+                               tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+                       }
+               } else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
                        if (err)
                                return err;
                } else if (err) {
@@ -14570,6 +14667,7 @@ static int tg3_phy_probe(struct tg3 *tp)
        if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
            (tg3_asic_rev(tp) == ASIC_REV_5719 ||
             tg3_asic_rev(tp) == ASIC_REV_5720 ||
+            tg3_asic_rev(tp) == ASIC_REV_57766 ||
             tg3_asic_rev(tp) == ASIC_REV_5762 ||
             (tg3_asic_rev(tp) == ASIC_REV_5717 &&
              tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
@@ -15379,6 +15477,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0)
                tp->fw_needed = FIRMWARE_TG3;
 
+       if (tg3_asic_rev(tp) == ASIC_REV_57766)
+               tp->fw_needed = FIRMWARE_TG357766;
+
        tp->irq_max = 1;
 
        if (tg3_flag(tp, 5750_PLUS)) {
@@ -15839,6 +15940,11 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        udelay(50);
        tg3_nvram_init(tp);
 
+       /* If the device has an NVRAM, no need to load patch firmware */
+       if (tg3_asic_rev(tp) == ASIC_REV_57766 &&
+           !tg3_flag(tp, NO_NVRAM))
+               tp->fw_needed = NULL;
+
        grc_misc_cfg = tr32(GRC_MISC_CFG);
        grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
 
index b5098f0d0e8f178dd5144b56399508b90f37d259..1cdc1b641c774bbee440b03d03146f5f052d65ec 100644 (file)
 #define  NIC_SRAM_MBUF_POOL_BASE5705   0x00010000
 #define  NIC_SRAM_MBUF_POOL_SIZE5705   0x0000e000
 
+#define TG3_SRAM_RXCPU_SCRATCH_BASE_57766      0x00030000
+#define  TG3_SRAM_RXCPU_SCRATCH_SIZE_57766      0x00010000
+#define TG3_57766_FW_BASE_ADDR                 0x00030000
+#define TG3_57766_FW_HANDSHAKE                 0x0003fccc
+#define TG3_SBROM_IN_SERVICE_LOOP              0x51
+
 #define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700      128
 #define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755      64
 #define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906      32