Skip to content

Commit

Permalink
tg3: Download 57766 EEE service patch firmware
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nithin Sujir authored and David S. Miller committed Mar 7, 2013
1 parent 31f11a9 commit c4dab50
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 16 deletions.
138 changes: 122 additions & 16 deletions drivers/net/ethernet/broadcom/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) ||
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/broadcom/tg3.h
Original file line number Diff line number Diff line change
Expand Up @@ -2222,6 +2222,12 @@
#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
Expand Down

0 comments on commit c4dab50

Please sign in to comment.