[TG3]: Fix low power state
authorMichael Chan <mchan@broadcom.com>
Wed, 14 Dec 2005 05:15:53 +0000 (21:15 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 14 Dec 2005 05:15:53 +0000 (21:15 -0800)
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 <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tg3.c
drivers/net/tg3.h

index a143c18c7bc6d997cb83290ebded6e5335f41ba2..a23ed28a72b820d495c4ee8c34ce5a7f6276cb2f 100644 (file)
@@ -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);
index fb7e2a5f4a088baa0c683f36dfeca1aaf7ff8517..94dbcf3537ec290e5b11e4481ce589fd673dcde5 100644 (file)
 #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
 #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 */