|
@@ -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;
|
|
|
|