From 381291b7d3e17ac966498312dc571dcca1b93efc Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 13 Dec 2005 21:08:21 -0800 Subject: [TG3]: Fix nvram arbitration bugs. The nvram arbitration rules were not strictly followed in a few places and this could lead to reading corrupted values from the nvram. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 47bd4a39442..dabc39befd3 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8533,6 +8533,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { tp->tg3_flags |= TG3_FLAG_NVRAM; + tg3_nvram_lock(tp); tg3_enable_nvram_access(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) @@ -8543,6 +8544,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_nvram_size(tp); tg3_disable_nvram_access(tp); + tg3_nvram_unlock(tp); } else { tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); @@ -8640,10 +8642,10 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) if (ret == 0) *val = swab32(tr32(NVRAM_RDDATA)); - tg3_nvram_unlock(tp); - tg3_disable_nvram_access(tp); + tg3_nvram_unlock(tp); + return ret; } @@ -8728,6 +8730,10 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len, offset = offset + (pagesize - page_off); + /* Nvram lock released by tg3_nvram_read() above, + * so need to get it again. + */ + tg3_nvram_lock(tp); tg3_enable_nvram_access(tp); /* -- cgit v1.2.3 From 6a9eba15f51c56da637e45ea1316eaa2a848986a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 13 Dec 2005 21:08:58 -0800 Subject: [TG3]: Fix suspend and resume Fix tg3_suspend() and tg3_resume() by clearing and setting the TG3_FLAG_INIT_COMPLETE flag when appropriate. tg3_set_power_state() looks at TG3_FLAG_INIT_COMPLETE on the peer device to determine when to appropriately switch to aux power. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index dabc39befd3..6b7ab4b7275 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10826,12 +10826,14 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) tg3_full_lock(tp, 0); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; tg3_full_unlock(tp); err = tg3_set_power_state(tp, pci_choose_state(pdev, state)); if (err) { tg3_full_lock(tp, 0); + tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tg3_init_hw(tp); tp->timer.expires = jiffies + tp->timer_offset; @@ -10865,6 +10867,7 @@ static int tg3_resume(struct pci_dev *pdev) tg3_full_lock(tp, 0); + tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; tg3_init_hw(tp); tp->timer.expires = jiffies + tp->timer_offset; -- cgit v1.2.3 From 16fe9d74f14ed74af778c5db7f9129e29916f4a7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 13 Dec 2005 21:09:54 -0800 Subject: [TG3]: Fix 5704 single-port mode If the dual-port 5704 is configured as a single-port device with only one PCI function, it would trigger a BUG() condition in tg3_find_5704_peer(). This fixes the problem by returning its own pdev if the peer cannot be found. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6b7ab4b7275..a143c18c7bc 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10443,8 +10443,13 @@ static struct pci_dev * __devinit tg3_find_5704_peer(struct tg3 *tp) break; pci_dev_put(peer); } - if (!peer || peer == tp->pdev) - BUG(); + /* 5704 can be configured in single-port mode, set peer to + * tp->pdev in that case. + */ + if (!peer) { + peer = tp->pdev; + return peer; + } /* * We don't need to keep the refcount elevated; there's no way -- cgit v1.2.3 From 6921d201f77e14848df2eaa597e26525f468abea Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Tue, 13 Dec 2005 21:15:53 -0800 Subject: [TG3]: Fix low power state Fix the following bugs in tg3_set_power_state(): 1. Both WOL and ASF flags require switching to aux power. 2. Add a missing handshake with firmware to enable WOL. 3. Turn off the PHY if both WOL and ASF are disabled. 4. Add nvram arbitration before halting the firmware. 5. Fix tg3_setup_copper_phy() to switch to 100Mbps when changing to low power state. Update revision and date. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 44 +++++++++++++++++++++++++++++++++++++++----- drivers/net/tg3.h | 7 +++++++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index a143c18c7bc..a23ed28a72b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.44" -#define DRV_MODULE_RELDATE "Dec 6, 2005" +#define DRV_MODULE_VERSION "3.45" +#define DRV_MODULE_RELDATE "Dec 13, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1025,7 +1025,9 @@ static void tg3_frob_aux_power(struct tg3 *tp) if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 || - (tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0) { + (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0 || + (tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 || + (tp_peer->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | @@ -1105,6 +1107,8 @@ static int tg3_setup_phy(struct tg3 *, int); static void tg3_write_sig_post_reset(struct tg3 *, int); static int tg3_halt_cpu(struct tg3 *, u32); +static int tg3_nvram_lock(struct tg3 *); +static void tg3_nvram_unlock(struct tg3 *); static int tg3_set_power_state(struct tg3 *tp, int state) { @@ -1179,6 +1183,21 @@ static int tg3_set_power_state(struct tg3 *tp, int state) tg3_setup_phy(tp, 0); } + if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + int i; + u32 val; + + for (i = 0; i < 200; i++) { + tg3_read_mem(tp, NIC_SRAM_FW_ASF_STATUS_MBOX, &val); + if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1) + break; + msleep(1); + } + } + tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE | + WOL_DRV_STATE_SHUTDOWN | + WOL_DRV_WOL | WOL_SET_MAGIC_PKT); + pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { @@ -1268,6 +1287,17 @@ static int tg3_set_power_state(struct tg3 *tp, int state) } } + if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + /* Turn off the PHY */ + if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { + tg3_writephy(tp, MII_TG3_EXT_CTRL, + MII_TG3_EXT_CTRL_FORCE_LED_OFF); + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); + tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); + } + } + tg3_frob_aux_power(tp); /* Workaround for unstable PLL clock */ @@ -1277,8 +1307,12 @@ static int tg3_set_power_state(struct tg3 *tp, int state) val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1); tw32(0x7d00, val); - if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { + tg3_nvram_lock(tp); tg3_halt_cpu(tp, RX_CPU_BASE); + tw32_f(NVRAM_SWARB, SWARB_REQ_CLR0); + tg3_nvram_unlock(tp); + } } /* Finally, set the new power state. */ @@ -1812,7 +1846,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) } } relink: - if (current_link_up == 0) { + if (current_link_up == 0 || tp->link_config.phy_is_low_power) { u32 tmp; tg3_phy_copper_begin(tp); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index fb7e2a5f4a0..94dbcf3537e 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1529,6 +1529,12 @@ #define NIC_SRAM_MAC_ADDR_HIGH_MBOX 0x00000c14 #define NIC_SRAM_MAC_ADDR_LOW_MBOX 0x00000c18 +#define NIC_SRAM_WOL_MBOX 0x00000d30 +#define WOL_SIGNATURE 0x474c0000 +#define WOL_DRV_STATE_SHUTDOWN 0x00000001 +#define WOL_DRV_WOL 0x00000002 +#define WOL_SET_MAGIC_PKT 0x00000004 + #define NIC_SRAM_DATA_CFG_2 0x00000d38 #define SHASTA_EXT_LED_MODE_MASK 0x00018000 @@ -1565,6 +1571,7 @@ #define MII_TG3_EXT_CTRL 0x10 /* Extended control register */ #define MII_TG3_EXT_CTRL_FIFO_ELASTIC 0x0001 #define MII_TG3_EXT_CTRL_LNK3_LED_MODE 0x0002 +#define MII_TG3_EXT_CTRL_FORCE_LED_OFF 0x0008 #define MII_TG3_EXT_CTRL_TBI 0x8000 #define MII_TG3_EXT_STAT 0x11 /* Extended status register */ -- cgit v1.2.3