tg3: Cleanup firmware parsing code
[cascardo/linux.git] / drivers / net / ethernet / broadcom / tg3.c
index fdb9b56..87bd0e3 100644 (file)
@@ -3452,11 +3452,58 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 #define TX_CPU_SCRATCH_SIZE    0x04000
 
 /* tp->lock is held. */
-static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
+static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
 {
        int i;
+       const int iters = 10000;
 
-       BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
+       for (i = 0; i < iters; i++) {
+               tw32(cpu_base + CPU_STATE, 0xffffffff);
+               tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
+               if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
+                       break;
+       }
+
+       return (i == iters) ? -EBUSY : 0;
+}
+
+/* tp->lock is held. */
+static int tg3_rxcpu_pause(struct tg3 *tp)
+{
+       int rc = tg3_pause_cpu(tp, RX_CPU_BASE);
+
+       tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+       tw32_f(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
+       udelay(10);
+
+       return rc;
+}
+
+/* tp->lock is held. */
+static int tg3_txcpu_pause(struct tg3 *tp)
+{
+       return tg3_pause_cpu(tp, TX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static void tg3_resume_cpu(struct tg3 *tp, u32 cpu_base)
+{
+       tw32(cpu_base + CPU_STATE, 0xffffffff);
+       tw32_f(cpu_base + CPU_MODE,  0x00000000);
+}
+
+/* tp->lock is held. */
+static void tg3_rxcpu_resume(struct tg3 *tp)
+{
+       tg3_resume_cpu(tp, RX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static int tg3_halt_cpu(struct tg3 *tp, u32 cpu_base)
+{
+       int rc;
+
+       BUG_ON(cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
 
        if (tg3_asic_rev(tp) == ASIC_REV_5906) {
                u32 val = tr32(GRC_VCPU_EXT_CTRL);
@@ -3464,17 +3511,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
                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);
-                       tw32(offset + CPU_MODE,  CPU_MODE_HALT);
-                       if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
-                               break;
-               }
-
-               tw32(offset + CPU_STATE, 0xffffffff);
-               tw32_f(offset + CPU_MODE,  CPU_MODE_HALT);
-               udelay(10);
+       if (cpu_base == RX_CPU_BASE) {
+               rc = tg3_rxcpu_pause(tp);
        } else {
                /*
                 * There is only an Rx CPU for the 5750 derivative in the
@@ -3483,17 +3521,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
                if (tg3_flag(tp, IS_SSB_CORE))
                        return 0;
 
-               for (i = 0; i < 10000; i++) {
-                       tw32(offset + CPU_STATE, 0xffffffff);
-                       tw32(offset + CPU_MODE,  CPU_MODE_HALT);
-                       if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
-                               break;
-               }
+               rc = tg3_txcpu_pause(tp);
        }
 
-       if (i >= 10000) {
+       if (rc) {
                netdev_err(tp->dev, "%s timed out, %s CPU\n",
-                          __func__, offset == RX_CPU_BASE ? "RX" : "TX");
+                          __func__, cpu_base == RX_CPU_BASE ? "RX" : "TX");
                return -ENODEV;
        }
 
@@ -3503,19 +3536,14 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
        return 0;
 }
 
-struct fw_info {
-       unsigned int fw_base;
-       unsigned int fw_len;
-       const __be32 *fw_data;
-};
-
 /* tp->lock is held. */
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
                                 u32 cpu_scratch_base, int cpu_scratch_size,
-                                struct fw_info *info)
+                                const struct tg3_firmware_hdr *fw_hdr)
 {
        int err, lock_err, i;
        void (*write_op)(struct tg3 *, u32, u32);
+       u32 *fw_data = (u32 *)(fw_hdr + 1);
 
        if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
                netdev_err(tp->dev,
@@ -3543,11 +3571,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
                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 < (info->fw_len / sizeof(u32)); i++)
-               write_op(tp, (cpu_scratch_base +
-                             (info->fw_base & 0xffff) +
-                             (i * sizeof(u32))),
-                             be32_to_cpu(info->fw_data[i]));
+       for (i = 0; i < (tp->fw->size - TG3_FW_HDR_LEN) / sizeof(u32); i++)
+               write_op(tp, cpu_scratch_base +
+                            (be32_to_cpu(fw_hdr->base_addr) & 0xffff) +
+                            (i * sizeof(u32)),
+                        be32_to_cpu(fw_data[i]));
+
 
        err = 0;
 
@@ -3555,14 +3584,34 @@ out:
        return err;
 }
 
+/* tp->lock is held. */
+static int tg3_pause_cpu_and_set_pc(struct tg3 *tp, u32 cpu_base, u32 pc)
+{
+       int i;
+       const int iters = 5;
+
+       tw32(cpu_base + CPU_STATE, 0xffffffff);
+       tw32_f(cpu_base + CPU_PC, pc);
+
+       for (i = 0; i < iters; i++) {
+               if (tr32(cpu_base + CPU_PC) == pc)
+                       break;
+               tw32(cpu_base + CPU_STATE, 0xffffffff);
+               tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
+               tw32_f(cpu_base + CPU_PC, pc);
+               udelay(1000);
+       }
+
+       return (i == iters) ? -EBUSY : 0;
+}
+
 /* tp->lock is held. */
 static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 {
-       struct fw_info info;
-       const __be32 *fw_data;
-       int err, i;
+       const struct tg3_firmware_hdr *fw_hdr;
+       int err;
 
-       fw_data = (void *)tp->fw->data;
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
        /* Firmware blob starts with version numbers, followed by
           start address and length. We are setting complete length.
@@ -3570,42 +3619,30 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
           Remainder is the blob to be loaded contiguously
           from start address. */
 
-       info.fw_base = be32_to_cpu(fw_data[1]);
-       info.fw_len = tp->fw->size - 12;
-       info.fw_data = &fw_data[3];
-
        err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
                                    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
-                                   &info);
+                                   fw_hdr);
        if (err)
                return err;
 
        err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
                                    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
-                                   &info);
+                                   fw_hdr);
        if (err)
                return err;
 
        /* Now startup only the RX cpu. */
-       tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-       tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
-
-       for (i = 0; i < 5; i++) {
-               if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
-                       break;
-               tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-               tw32(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
-               tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
-               udelay(1000);
-       }
-       if (i >= 5) {
+       err = tg3_pause_cpu_and_set_pc(tp, RX_CPU_BASE,
+                                      be32_to_cpu(fw_hdr->base_addr));
+       if (err) {
                netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
                           "should be %08x\n", __func__,
-                          tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
+                          tr32(RX_CPU_BASE + CPU_PC),
+                               be32_to_cpu(fw_hdr->base_addr));
                return -ENODEV;
        }
-       tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
-       tw32_f(RX_CPU_BASE + CPU_MODE,  0x00000000);
+
+       tg3_rxcpu_resume(tp);
 
        return 0;
 }
@@ -3613,17 +3650,14 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 /* tp->lock is held. */
 static int tg3_load_tso_firmware(struct tg3 *tp)
 {
-       struct fw_info info;
-       const __be32 *fw_data;
+       const struct tg3_firmware_hdr *fw_hdr;
        unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
-       int err, i;
+       int err;
 
-       if (tg3_flag(tp, HW_TSO_1) ||
-           tg3_flag(tp, HW_TSO_2) ||
-           tg3_flag(tp, HW_TSO_3))
+       if (!tg3_flag(tp, FW_TSO))
                return 0;
 
-       fw_data = (void *)tp->fw->data;
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
        /* Firmware blob starts with version numbers, followed by
           start address and length. We are setting complete length.
@@ -3631,10 +3665,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
           Remainder is the blob to be loaded contiguously
           from start address. */
 
-       info.fw_base = be32_to_cpu(fw_data[1]);
        cpu_scratch_size = tp->fw_len;
-       info.fw_len = tp->fw->size - 12;
-       info.fw_data = &fw_data[3];
 
        if (tg3_asic_rev(tp) == ASIC_REV_5705) {
                cpu_base = RX_CPU_BASE;
@@ -3647,30 +3678,22 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
 
        err = tg3_load_firmware_cpu(tp, cpu_base,
                                    cpu_scratch_base, cpu_scratch_size,
-                                   &info);
+                                   fw_hdr);
        if (err)
                return err;
 
        /* Now startup the cpu. */
-       tw32(cpu_base + CPU_STATE, 0xffffffff);
-       tw32_f(cpu_base + CPU_PC, info.fw_base);
-
-       for (i = 0; i < 5; i++) {
-               if (tr32(cpu_base + CPU_PC) == info.fw_base)
-                       break;
-               tw32(cpu_base + CPU_STATE, 0xffffffff);
-               tw32(cpu_base + CPU_MODE,  CPU_MODE_HALT);
-               tw32_f(cpu_base + CPU_PC, info.fw_base);
-               udelay(1000);
-       }
-       if (i >= 5) {
+       err = tg3_pause_cpu_and_set_pc(tp, cpu_base,
+                                      be32_to_cpu(fw_hdr->base_addr));
+       if (err) {
                netdev_err(tp->dev,
                           "%s fails to set CPU PC, is %08x should be %08x\n",
-                          __func__, tr32(cpu_base + CPU_PC), info.fw_base);
+                          __func__, tr32(cpu_base + CPU_PC),
+                          be32_to_cpu(fw_hdr->base_addr));
                return -ENODEV;
        }
-       tw32(cpu_base + CPU_STATE, 0xffffffff);
-       tw32_f(cpu_base + CPU_MODE,  0x00000000);
+
+       tg3_resume_cpu(tp, cpu_base);
        return 0;
 }
 
@@ -10566,7 +10589,7 @@ static int tg3_test_msi(struct tg3 *tp)
 
 static int tg3_request_firmware(struct tg3 *tp)
 {
-       const __be32 *fw_data;
+       const struct tg3_firmware_hdr *fw_hdr;
 
        if (request_firmware(&tp->fw, tp->fw_needed, &tp->pdev->dev)) {
                netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
@@ -10574,15 +10597,15 @@ static int tg3_request_firmware(struct tg3 *tp)
                return -ENOENT;
        }
 
-       fw_data = (void *)tp->fw->data;
+       fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
 
        /* Firmware blob starts with version numbers, followed by
         * start address and _full_ length including BSS sections
         * (which must be longer than the actual data, of course
         */
 
-       tp->fw_len = be32_to_cpu(fw_data[2]);   /* includes bss */
-       if (tp->fw_len < (tp->fw->size - 12)) {
+       tp->fw_len = be32_to_cpu(fw_hdr->len);  /* includes bss */
+       if (tp->fw_len < (tp->fw->size - TG3_FW_HDR_LEN)) {
                netdev_err(tp->dev, "bogus length %d in \"%s\"\n",
                           tp->fw_len, tp->fw_needed);
                release_firmware(tp->fw);
@@ -15293,7 +15316,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        } else if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
                   tg3_asic_rev(tp) != ASIC_REV_5701 &&
                   tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
-                       tg3_flag_set(tp, TSO_BUG);
+               tg3_flag_set(tp, FW_TSO);
+               tg3_flag_set(tp, TSO_BUG);
                if (tg3_asic_rev(tp) == ASIC_REV_5705)
                        tp->fw_needed = FIRMWARE_TG3TSO5;
                else
@@ -15304,7 +15328,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
        if (tg3_flag(tp, HW_TSO_1) ||
            tg3_flag(tp, HW_TSO_2) ||
            tg3_flag(tp, HW_TSO_3) ||
-           tp->fw_needed) {
+           tg3_flag(tp, FW_TSO)) {
                /* For firmware TSO, assume ASF is disabled.
                 * We'll disable TSO later if we discover ASF
                 * is enabled in tg3_get_eeprom_hw_cfg().
@@ -15591,7 +15615,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
         */
        tg3_get_eeprom_hw_cfg(tp);
 
-       if (tp->fw_needed && tg3_flag(tp, ENABLE_ASF)) {
+       if (tg3_flag(tp, FW_TSO) && tg3_flag(tp, ENABLE_ASF)) {
                tg3_flag_clear(tp, TSO_CAPABLE);
                tg3_flag_clear(tp, TSO_BUG);
                tp->fw_needed = NULL;