@@ -35,6 +35,11 @@ $(stampdir)/stamp-prepare-%: $(confdir)/$(arch)
@echo "Preparing $*..."
install -d $(builddir)/build-$*
cd updates; tar cf - * | tar -C $(builddir)/build-$* -xf -
+ if ls debian/patches/*.patch; then \
+ for i in debian/patches/*.patch; do \
+ patch -d $(builddir)/build-$* -p2 < $$i; \
+ done; \
+ fi
#
# compat-wireless preparation
#
--
1.7.0.4
From 2a031ba9ec60dffac86ea99a15b5cdacc32094bb Mon Sep 17 00:00:00 2001
From: Tim Gardner <tim.gardner@canonical.com>
Date: Mon, 23 Aug 2010 10:22:12 -0600
Subject: [PATCH 2/2] UBUNTU: Update atl1c to 1.0.1.0-NAPI from 2.6.36-rc2
BugLink: http://bugs.launchpad.net/bugs/614426
This updates the atl1c driver in compat-wireless-2.6.35 to 1.0.1.0-NAPI.
Do it using the patch infrastructure so as not to lose the update when next
compat-wireless-2.6.35 is updated from stable.
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
---
...ate-atl1c-to-1.0.1.0-NAPI-from-2.6.36-rc2.patch | 1033 ++++++++++++++++++++
1 files changed, 1033 insertions(+), 0 deletions(-)
create mode 100644 debian/patches/0001-UBUNTU-Update-atl1c-to-1.0.1.0-NAPI-from-2.6.36-rc2.patch
new file mode 100644
@@ -0,0 +1,1033 @@
+From 642a3786bfe28a4cb38bd5e29c378c1e209448c0 Mon Sep 17 00:00:00 2001
+From: Tim Gardner <tim.gardner@canonical.com>
+Date: Mon, 23 Aug 2010 08:35:46 -0600
+Subject: [PATCH] UBUNTU: Update atl1c to 1.0.1.0-NAPI from 2.6.36-rc2
+
+Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
+---
+ .../drivers/net/atl1c/atl1c.h | 9 +-
+ .../drivers/net/atl1c/atl1c_hw.c | 107 +++++-
+ .../drivers/net/atl1c/atl1c_hw.h | 49 +++-
+ .../drivers/net/atl1c/atl1c_main.c | 350 +++++++++++---------
+ 4 files changed, 346 insertions(+), 169 deletions(-)
+
+diff --git a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c.h b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c.h
+index 84ae905..52abbbd 100644
+--- a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c.h
++++ b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c.h
+@@ -73,7 +73,8 @@
+ #define FULL_DUPLEX 2
+
+ #define AT_RX_BUF_SIZE (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
+-#define MAX_JUMBO_FRAME_SIZE (9*1024)
++#define MAX_JUMBO_FRAME_SIZE (6*1024)
++#define MAX_TSO_FRAME_SIZE (7*1024)
+ #define MAX_TX_OFFLOAD_THRESH (9*1024)
+
+ #define AT_MAX_RECEIVE_QUEUE 4
+@@ -87,10 +88,11 @@
+ #define AT_MAX_INT_WORK 5
+ #define AT_TWSI_EEPROM_TIMEOUT 100
+ #define AT_HW_MAX_IDLE_DELAY 10
+-#define AT_SUSPEND_LINK_TIMEOUT 28
++#define AT_SUSPEND_LINK_TIMEOUT 100
+
+ #define AT_ASPM_L0S_TIMER 6
+ #define AT_ASPM_L1_TIMER 12
++#define AT_LCKDET_TIMER 12
+
+ #define ATL1C_PCIE_L0S_L1_DISABLE 0x01
+ #define ATL1C_PCIE_PHY_RESET 0x02
+@@ -316,6 +318,7 @@ enum atl1c_nic_type {
+ athr_l2c_b,
+ athr_l2c_b2,
+ athr_l1d,
++ athr_l1d_2,
+ };
+
+ enum atl1c_trans_queue {
+@@ -392,6 +395,8 @@ struct atl1c_hw {
+ u16 subsystem_id;
+ u16 subsystem_vendor_id;
+ u8 revision_id;
++ u16 phy_id1;
++ u16 phy_id2;
+
+ u32 intr_mask;
+ u8 dmaw_dly_cnt;
+diff --git a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.c b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.c
+index f1389d6..d8501f0 100644
+--- a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.c
++++ b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.c
+@@ -37,6 +37,9 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
+ if (data & TWSI_DEBUG_DEV_EXIST)
+ return 1;
+
++ AT_READ_REG(hw, REG_MASTER_CTRL, &data);
++ if (data & MASTER_CTRL_OTP_SEL)
++ return 1;
+ return 0;
+ }
+
+@@ -69,6 +72,8 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+ u32 i;
+ u32 otp_ctrl_data;
+ u32 twsi_ctrl_data;
++ u32 ltssm_ctrl_data;
++ u32 wol_data;
+ u8 eth_addr[ETH_ALEN];
+ u16 phy_data;
+ bool raise_vol = false;
+@@ -104,6 +109,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+ udelay(20);
+ raise_vol = true;
+ }
++ /* close open bit of ReadOnly*/
++ AT_READ_REG(hw, REG_LTSSM_ID_CTRL, <ssm_ctrl_data);
++ ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
++ AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);
++
++ /* clear any WOL settings */
++ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
++ AT_READ_REG(hw, REG_WOL_CTRL, &wol_data);
++
+
+ AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
+ twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
+@@ -119,17 +133,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+ }
+ /* Disable OTP_CLK */
+ if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
+- if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
+- otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+- AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+- AT_WRITE_FLUSH(hw);
+- msleep(1);
+- }
++ otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
++ AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
++ msleep(1);
+ }
+ if (raise_vol) {
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l2c_b2 ||
+- hw->nic_type == athr_l1d) {
++ hw->nic_type == athr_l1d ||
++ hw->nic_type == athr_l1d_2) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
+ if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
+ goto out;
+@@ -456,14 +468,22 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
+
+ if (hw->nic_type == athr_l2c_b ||
+ hw->nic_type == athr_l2c_b2 ||
+- hw->nic_type == athr_l1d) {
++ hw->nic_type == athr_l1d ||
++ hw->nic_type == athr_l1d_2) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
+ atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
+ msleep(20);
+ }
+-
+- /*Enable PHY LinkChange Interrupt */
++ if (hw->nic_type == athr_l1d) {
++ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
++ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
++ }
++ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
++ || hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
++ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
++ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
++ }
+ err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
+ if (err) {
+ if (netif_msg_hw(adapter))
+@@ -482,12 +502,10 @@ int atl1c_phy_init(struct atl1c_hw *hw)
+ struct pci_dev *pdev = adapter->pdev;
+ int ret_val;
+ u16 mii_bmcr_data = BMCR_RESET;
+- u16 phy_id1, phy_id2;
+
+- if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
+- (atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
+- if (netif_msg_link(adapter))
+- dev_err(&pdev->dev, "Error get phy ID\n");
++ if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
++ (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
++ dev_err(&pdev->dev, "Error get phy ID\n");
+ return -1;
+ }
+ switch (hw->media_type) {
+@@ -572,6 +590,65 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
+ return 0;
+ }
+
++int atl1c_phy_power_saving(struct atl1c_hw *hw)
++{
++ struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
++ struct pci_dev *pdev = adapter->pdev;
++ int ret = 0;
++ u16 autoneg_advertised = ADVERTISED_10baseT_Half;
++ u16 save_autoneg_advertised;
++ u16 phy_data;
++ u16 mii_lpa_data;
++ u16 speed = SPEED_0;
++ u16 duplex = FULL_DUPLEX;
++ int i;
++
++ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
++ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
++ if (phy_data & BMSR_LSTATUS) {
++ atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
++ if (mii_lpa_data & LPA_10FULL)
++ autoneg_advertised = ADVERTISED_10baseT_Full;
++ else if (mii_lpa_data & LPA_10HALF)
++ autoneg_advertised = ADVERTISED_10baseT_Half;
++ else if (mii_lpa_data & LPA_100HALF)
++ autoneg_advertised = ADVERTISED_100baseT_Half;
++ else if (mii_lpa_data & LPA_100FULL)
++ autoneg_advertised = ADVERTISED_100baseT_Full;
++
++ save_autoneg_advertised = hw->autoneg_advertised;
++ hw->phy_configured = false;
++ hw->autoneg_advertised = autoneg_advertised;
++ if (atl1c_restart_autoneg(hw) != 0) {
++ dev_dbg(&pdev->dev, "phy autoneg failed\n");
++ ret = -1;
++ }
++ hw->autoneg_advertised = save_autoneg_advertised;
++
++ if (mii_lpa_data) {
++ for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
++ mdelay(100);
++ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
++ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
++ if (phy_data & BMSR_LSTATUS) {
++ if (atl1c_get_speed_and_duplex(hw, &speed,
++ &duplex) != 0)
++ dev_dbg(&pdev->dev,
++ "get speed and duplex failed\n");
++ break;
++ }
++ }
++ }
++ } else {
++ speed = SPEED_10;
++ duplex = HALF_DUPLEX;
++ }
++ adapter->link_speed = speed;
++ adapter->link_duplex = duplex;
++
++ return ret;
++}
++
+ int atl1c_restart_autoneg(struct atl1c_hw *hw)
+ {
+ int err = 0;
+diff --git a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.h b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.h
+index 1eeb3ed..3dd6759 100644
+--- a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.h
++++ b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_hw.h
+@@ -42,7 +42,7 @@ bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
+ int atl1c_phy_init(struct atl1c_hw *hw);
+ int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
+ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+-
++int atl1c_phy_power_saving(struct atl1c_hw *hw);
+ /* register definition */
+ #define REG_DEVICE_CAP 0x5C
+ #define DEVICE_CAP_MAX_PAYLOAD_MASK 0x7
+@@ -120,6 +120,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define REG_PCIE_PHYMISC 0x1000
+ #define PCIE_PHYMISC_FORCE_RCV_DET 0x4
+
++#define REG_PCIE_PHYMISC2 0x1004
++#define PCIE_PHYMISC2_SERDES_CDR_MASK 0x3
++#define PCIE_PHYMISC2_SERDES_CDR_SHIFT 16
++#define PCIE_PHYMISC2_SERDES_TH_MASK 0x3
++#define PCIE_PHYMISC2_SERDES_TH_SHIFT 18
++
+ #define REG_TWSI_DEBUG 0x1108
+ #define TWSI_DEBUG_DEV_EXIST 0x20000000
+
+@@ -150,24 +156,28 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define PM_CTRL_ASPM_L0S_EN 0x00001000
+ #define PM_CTRL_CLK_SWH_L1 0x00002000
+ #define PM_CTRL_CLK_PWM_VER1_1 0x00004000
+-#define PM_CTRL_PCIE_RECV 0x00008000
++#define PM_CTRL_RCVR_WT_TIMER 0x00008000
+ #define PM_CTRL_L1_ENTRY_TIMER_MASK 0xF
+ #define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16
+ #define PM_CTRL_PM_REQ_TIMER_MASK 0xF
+ #define PM_CTRL_PM_REQ_TIMER_SHIFT 20
+-#define PM_CTRL_LCKDET_TIMER_MASK 0x3F
++#define PM_CTRL_LCKDET_TIMER_MASK 0xF
+ #define PM_CTRL_LCKDET_TIMER_SHIFT 24
+ #define PM_CTRL_EN_BUFS_RX_L0S 0x10000000
+ #define PM_CTRL_SA_DLY_EN 0x20000000
+ #define PM_CTRL_MAC_ASPM_CHK 0x40000000
+ #define PM_CTRL_HOTRST 0x80000000
+
++#define REG_LTSSM_ID_CTRL 0x12FC
++#define LTSSM_ID_EN_WRO 0x1000
+ /* Selene Master Control Register */
+ #define REG_MASTER_CTRL 0x1400
+ #define MASTER_CTRL_SOFT_RST 0x1
+ #define MASTER_CTRL_TEST_MODE_MASK 0x3
+ #define MASTER_CTRL_TEST_MODE_SHIFT 2
+ #define MASTER_CTRL_BERT_START 0x10
++#define MASTER_CTRL_OOB_DIS_OFF 0x40
++#define MASTER_CTRL_SA_TIMER_EN 0x80
+ #define MASTER_CTRL_MTIMER_EN 0x100
+ #define MASTER_CTRL_MANUAL_INT 0x200
+ #define MASTER_CTRL_TX_ITIMER_EN 0x400
+@@ -220,6 +230,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ GPHY_CTRL_PWDOWN_HW |\
+ GPHY_CTRL_PHY_IDDQ)
+
++#define GPHY_CTRL_POWER_SAVING ( \
++ GPHY_CTRL_SEL_ANA_RST |\
++ GPHY_CTRL_HIB_EN |\
++ GPHY_CTRL_HIB_PULSE |\
++ GPHY_CTRL_PWDOWN_HW |\
++ GPHY_CTRL_PHY_IDDQ)
+ /* Block IDLE Status Register */
+ #define REG_IDLE_STATUS 0x1410
+ #define IDLE_STATUS_MASK 0x00FF
+@@ -287,6 +303,14 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define SERDES_LOCK_DETECT 0x1 /* SerDes lock detected. This signal
+ * comes from Analog SerDes */
+ #define SERDES_LOCK_DETECT_EN 0x2 /* 1: Enable SerDes Lock detect function */
++#define SERDES_LOCK_STS_SELFB_PLL_SHIFT 0xE
++#define SERDES_LOCK_STS_SELFB_PLL_MASK 0x3
++#define SERDES_OVCLK_18_25 0x0
++#define SERDES_OVCLK_12_18 0x1
++#define SERDES_OVCLK_0_4 0x2
++#define SERDES_OVCLK_4_12 0x3
++#define SERDES_MAC_CLK_SLOWDOWN 0x20000
++#define SERDES_PYH_CLK_SLOWDOWN 0x40000
+
+ /* MAC Control Register */
+ #define REG_MAC_CTRL 0x1480
+@@ -693,6 +717,21 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define REG_MAC_TX_STATUS_BIN 0x1760
+ #define REG_MAC_TX_STATUS_END 0x17c0
+
++#define REG_CLK_GATING_CTRL 0x1814
++#define CLK_GATING_DMAW_EN 0x0001
++#define CLK_GATING_DMAR_EN 0x0002
++#define CLK_GATING_TXQ_EN 0x0004
++#define CLK_GATING_RXQ_EN 0x0008
++#define CLK_GATING_TXMAC_EN 0x0010
++#define CLK_GATING_RXMAC_EN 0x0020
++
++#define CLK_GATING_EN_ALL (CLK_GATING_DMAW_EN |\
++ CLK_GATING_DMAR_EN |\
++ CLK_GATING_TXQ_EN |\
++ CLK_GATING_RXQ_EN |\
++ CLK_GATING_TXMAC_EN|\
++ CLK_GATING_RXMAC_EN)
++
+ /* DEBUG ADDR */
+ #define REG_DEBUG_DATA0 0x1900
+ #define REG_DEBUG_DATA1 0x1904
+@@ -734,6 +773,10 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+
+ #define MII_PHYSID1 0x02
+ #define MII_PHYSID2 0x03
++#define L1D_MPW_PHYID1 0xD01C /* V7 */
++#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */
++#define L1D_MPW_PHYID3 0xD01E /* V8 */
++
+
+ /* Autoneg Advertisement Register */
+ #define MII_ADVERTISE 0x04
+diff --git a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_main.c b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_main.c
+index f207d55..cd8f019 100644
+--- a/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_main.c
++++ b/updates/compat-wireless-2.6.35/drivers/net/atl1c/atl1c_main.c
+@@ -21,7 +21,7 @@
+
+ #include "atl1c.h"
+
+-#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
++#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
+ char atl1c_driver_name[] = "atl1c";
+ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
+ #define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062
+@@ -29,7 +29,7 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
+ #define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */
+ #define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */
+ #define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */
+-
++#define PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */
+ #define L2CB_V10 0xc0
+ #define L2CB_V11 0xc1
+
+@@ -97,7 +97,28 @@ static const u16 atl1c_rrd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] =
+
+ static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP;
++static void atl1c_pcie_patch(struct atl1c_hw *hw)
++{
++ u32 data;
+
++ AT_READ_REG(hw, REG_PCIE_PHYMISC, &data);
++ data |= PCIE_PHYMISC_FORCE_RCV_DET;
++ AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data);
++
++ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) {
++ AT_READ_REG(hw, REG_PCIE_PHYMISC2, &data);
++
++ data &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK <<
++ PCIE_PHYMISC2_SERDES_CDR_SHIFT);
++ data |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT;
++ data &= ~(PCIE_PHYMISC2_SERDES_TH_MASK <<
++ PCIE_PHYMISC2_SERDES_TH_SHIFT);
++ data |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT;
++ AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data);
++ }
++}
++
++/* FIXME: no need any more ? */
+ /*
+ * atl1c_init_pcie - init PCIE module
+ */
+@@ -127,6 +148,11 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
+ data &= ~PCIE_UC_SERVRITY_FCP;
+ AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data);
+
++ AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &data);
++ data &= ~LTSSM_ID_EN_WRO;
++ AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, data);
++
++ atl1c_pcie_patch(hw);
+ if (flag & ATL1C_PCIE_L0S_L1_DISABLE)
+ atl1c_disable_l0s_l1(hw);
+ if (flag & ATL1C_PCIE_PHY_RESET)
+@@ -135,7 +161,7 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
+ AT_WRITE_REG(hw, REG_GPHY_CTRL,
+ GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET);
+
+- msleep(1);
++ msleep(5);
+ }
+
+ /*
+@@ -159,6 +185,7 @@ static inline void atl1c_irq_disable(struct atl1c_adapter *adapter)
+ {
+ atomic_inc(&adapter->irq_sem);
+ AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
++ AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
+ AT_WRITE_FLUSH(&adapter->hw);
+ synchronize_irq(adapter->pdev->irq);
+ }
+@@ -231,15 +258,15 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
+
+ if ((phy_data & BMSR_LSTATUS) == 0) {
+ /* link down */
+- if (netif_carrier_ok(netdev)) {
+- hw->hibernate = true;
+- if (atl1c_stop_mac(hw) != 0)
+- if (netif_msg_hw(adapter))
+- dev_warn(&pdev->dev,
+- "stop mac failed\n");
+- atl1c_set_aspm(hw, false);
+- }
++ hw->hibernate = true;
++ if (atl1c_stop_mac(hw) != 0)
++ if (netif_msg_hw(adapter))
++ dev_warn(&pdev->dev, "stop mac failed\n");
++ atl1c_set_aspm(hw, false);
+ netif_carrier_off(netdev);
++ netif_stop_queue(netdev);
++ atl1c_phy_reset(hw);
++ atl1c_phy_init(&adapter->hw);
+ } else {
+ /* Link Up */
+ hw->hibernate = false;
+@@ -308,6 +335,7 @@ static void atl1c_common_task(struct work_struct *work)
+ netdev = adapter->netdev;
+
+ if (adapter->work_event & ATL1C_WORK_EVENT_RESET) {
++ adapter->work_event &= ~ATL1C_WORK_EVENT_RESET;
+ netif_device_detach(netdev);
+ atl1c_down(adapter);
+ atl1c_up(adapter);
+@@ -315,8 +343,11 @@ static void atl1c_common_task(struct work_struct *work)
+ return;
+ }
+
+- if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE)
++ if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) {
++ adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE;
+ atl1c_check_link_status(adapter);
++ }
++ return;
+ }
+
+
+@@ -480,6 +511,13 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
+ netdev->mtu = new_mtu;
+ adapter->hw.max_frame_size = new_mtu;
+ atl1c_set_rxbufsize(adapter, netdev);
++ if (new_mtu > MAX_TSO_FRAME_SIZE) {
++ adapter->netdev->features &= ~NETIF_F_TSO;
++ adapter->netdev->features &= ~NETIF_F_TSO6;
++ } else {
++ adapter->netdev->features |= NETIF_F_TSO;
++ adapter->netdev->features |= NETIF_F_TSO6;
++ }
+ atl1c_down(adapter);
+ atl1c_up(adapter);
+ clear_bit(__AT_RESETTING, &adapter->flags);
+@@ -617,6 +655,9 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
+ case PCI_DEVICE_ID_ATHEROS_L1D:
+ hw->nic_type = athr_l1d;
+ break;
++ case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
++ hw->nic_type = athr_l1d_2;
++ break;
+ default:
+ break;
+ }
+@@ -631,9 +672,7 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
+ AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data);
+ AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
+
+- hw->ctrl_flags = ATL1C_INTR_CLEAR_ON_READ |
+- ATL1C_INTR_MODRT_ENABLE |
+- ATL1C_RX_IPV6_CHKSUM |
++ hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE |
+ ATL1C_TXQ_MODE_ENHANCE;
+ if (link_ctrl_data & LINK_CTRL_L0S_EN)
+ hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
+@@ -641,12 +680,12 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
+ hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
+ if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
+ hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
++ hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+
+ if (hw->nic_type == athr_l1c ||
+- hw->nic_type == athr_l1d) {
+- hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
++ hw->nic_type == athr_l1d ||
++ hw->nic_type == athr_l1d_2)
+ hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
+- }
+ return 0;
+ }
+ /*
+@@ -661,6 +700,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
+ {
+ struct atl1c_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
++ u32 revision;
++
+
+ adapter->wol = 0;
+ adapter->link_speed = SPEED_0;
+@@ -673,7 +714,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
+ hw->device_id = pdev->device;
+ hw->subsystem_vendor_id = pdev->subsystem_vendor;
+ hw->subsystem_id = pdev->subsystem_device;
+-
++ AT_READ_REG(hw, PCI_CLASS_REVISION, &revision);
++ hw->revision_id = revision & 0xFF;
+ /* before link up, we assume hibernate is true */
+ hw->hibernate = true;
+ hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
+@@ -978,6 +1020,7 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
+ struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb;
+ struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb;
+ int i;
++ u32 data;
+
+ /* TPD */
+ AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI,
+@@ -1021,6 +1064,23 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
+ (u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32));
+ AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO,
+ (u32)(smb->dma & AT_DMA_LO_ADDR_MASK));
++ if (hw->nic_type == athr_l2c_b) {
++ AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L);
++ AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L);
++ AT_WRITE_REG(hw, REG_SRAM_RXF_ADDR, 0x029f0000L);
++ AT_WRITE_REG(hw, REG_SRAM_RFD0_INFO, 0x02bf02a0L);
++ AT_WRITE_REG(hw, REG_SRAM_TXF_ADDR, 0x03bf02c0L);
++ AT_WRITE_REG(hw, REG_SRAM_TRD_ADDR, 0x03df03c0L);
++ AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0); /* TX watermark, to enter l1 state.*/
++ AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0); /* RXD threshold.*/
++ }
++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d_2) {
++ /* Power Saving for L2c_B */
++ AT_READ_REG(hw, REG_SERDES_LOCK, &data);
++ data |= SERDES_MAC_CLK_SLOWDOWN;
++ data |= SERDES_PYH_CLK_SLOWDOWN;
++ AT_WRITE_REG(hw, REG_SERDES_LOCK, data);
++ }
+ /* Load all of base address above */
+ AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
+ }
+@@ -1033,6 +1093,7 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
+ u16 tx_offload_thresh;
+ u32 txq_ctrl_data;
+ u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */
++ u32 max_pay_load_data;
+
+ extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
+ tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
+@@ -1050,8 +1111,11 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
+ TXQ_NUM_TPD_BURST_SHIFT;
+ if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE)
+ txq_ctrl_data |= TXQ_CTRL_ENH_MODE;
+- txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
++ max_pay_load_data = (atl1c_pay_load_size[hw->dmar_block] &
+ TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2)
++ max_pay_load_data >>= 1;
++ txq_ctrl_data |= max_pay_load_data;
+
+ AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
+ }
+@@ -1082,7 +1146,7 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter)
+ rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) <<
+ RSS_HASH_BITS_SHIFT;
+ if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON)
+- rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_100M &
++ rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_1M &
+ ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
+
+ AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
+@@ -1202,21 +1266,23 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
+ {
+ struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+ struct pci_dev *pdev = adapter->pdev;
+- int ret;
++ u32 master_ctrl_data = 0;
+
+ AT_WRITE_REG(hw, REG_IMR, 0);
+ AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
+
+- ret = atl1c_stop_mac(hw);
+- if (ret)
+- return ret;
++ atl1c_stop_mac(hw);
+ /*
+ * Issue Soft Reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+- AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
++ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
++ master_ctrl_data |= MASTER_CTRL_OOB_DIS_OFF;
++ AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST)
++ & 0xFFFF));
++
+ AT_WRITE_FLUSH(hw);
+ msleep(10);
+ /* Wait at least 10ms for All module to be Idle */
+@@ -1257,42 +1323,39 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+ {
+ u32 pm_ctrl_data;
+ u32 link_ctrl_data;
++ u32 link_l1_timer = 0xF;
+
+ AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
+ AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
+- pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+
++ pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+ pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+ pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
+- PM_CTRL_LCKDET_TIMER_SHIFT);
+-
+- pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+- pm_ctrl_data |= PM_CTRL_RBER_EN;
+- pm_ctrl_data |= PM_CTRL_SDES_EN;
++ PM_CTRL_LCKDET_TIMER_SHIFT);
++ pm_ctrl_data |= AT_LCKDET_TIMER << PM_CTRL_LCKDET_TIMER_SHIFT;
+
+- if (hw->nic_type == athr_l2c_b ||
+- hw->nic_type == athr_l1d ||
+- hw->nic_type == athr_l2c_b2) {
++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
++ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
+ link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
+ if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
+- if (hw->nic_type == athr_l2c_b &&
+- hw->revision_id == L2CB_V10)
++ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10)
+ link_ctrl_data |= LINK_CTRL_EXT_SYNC;
+ }
+
+ AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
+
+- pm_ctrl_data |= PM_CTRL_PCIE_RECV;
+- pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
+- pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
++ pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER;
++ pm_ctrl_data &= ~(PM_CTRL_PM_REQ_TIMER_MASK <<
++ PM_CTRL_PM_REQ_TIMER_SHIFT);
++ pm_ctrl_data |= AT_ASPM_L1_TIMER <<
++ PM_CTRL_PM_REQ_TIMER_SHIFT;
+ pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
+ pm_ctrl_data &= ~PM_CTRL_HOTRST;
+ pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
+ }
+-
++ pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+ if (linkup) {
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+@@ -1301,27 +1364,26 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+ if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+ pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
+
+- if (hw->nic_type == athr_l2c_b ||
+- hw->nic_type == athr_l1d ||
+- hw->nic_type == athr_l2c_b2) {
++ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
++ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
+ if (hw->nic_type == athr_l2c_b)
+ if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
+- pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
++ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+ pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+- if (hw->adapter->link_speed == SPEED_100 ||
+- hw->adapter->link_speed == SPEED_1000) {
+- pm_ctrl_data &=
+- ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+- PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+- if (hw->nic_type == athr_l1d)
+- pm_ctrl_data |= 0xF <<
+- PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+- else
+- pm_ctrl_data |= 7 <<
+- PM_CTRL_L1_ENTRY_TIMER_SHIFT;
++ if (hw->adapter->link_speed == SPEED_100 ||
++ hw->adapter->link_speed == SPEED_1000) {
++ pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
++ PM_CTRL_L1_ENTRY_TIMER_SHIFT);
++ if (hw->nic_type == athr_l2c_b)
++ link_l1_timer = 7;
++ else if (hw->nic_type == athr_l2c_b2 ||
++ hw->nic_type == athr_l1d_2)
++ link_l1_timer = 4;
++ pm_ctrl_data |= link_l1_timer <<
++ PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ }
+ } else {
+ pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+@@ -1330,24 +1392,12 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+ pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+- }
+- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+- if (hw->adapter->link_speed == SPEED_10)
+- if (hw->nic_type == athr_l1d)
+- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
+- else
+- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+- else if (hw->adapter->link_speed == SPEED_100)
+- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
+- else
+- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
+
++ }
+ } else {
+- pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+-
+ pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+
+ if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
+@@ -1355,8 +1405,9 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+ else
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+ }
+-
+ AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data);
++
++ return;
+ }
+
+ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
+@@ -1395,7 +1446,8 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
+ mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
+
+ mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
+- if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
++ if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2 ||
++ hw->nic_type == athr_l1d_2) {
+ mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
+ mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
+ }
+@@ -1413,6 +1465,7 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
+ struct atl1c_hw *hw = &adapter->hw;
+ u32 master_ctrl_data = 0;
+ u32 intr_modrt_data;
++ u32 data;
+
+ /* clear interrupt status */
+ AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
+@@ -1422,6 +1475,15 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
+ * HW will enable self to assert interrupt event to system after
+ * waiting x-time for software to notify it accept interrupt.
+ */
++
++ data = CLK_GATING_EN_ALL;
++ if (hw->ctrl_flags & ATL1C_CLK_GATING_EN) {
++ if (hw->nic_type == athr_l2c_b)
++ data &= ~CLK_GATING_RXMAC_EN;
++ } else
++ data = 0;
++ AT_WRITE_REG(hw, REG_CLK_GATING_CTRL, data);
++
+ AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
+ hw->ict & INT_RETRIG_TIMER_MASK);
+
+@@ -1440,6 +1502,7 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
+ if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
+ master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
+
++ master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN;
+ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+
+ if (hw->ctrl_flags & ATL1C_CMB_ENABLE) {
+@@ -1628,11 +1691,9 @@ static irqreturn_t atl1c_intr(int irq, void *data)
+ "atl1c hardware error (status = 0x%x)\n",
+ status & ISR_ERROR);
+ /* reset MAC */
+- hw->intr_mask &= ~ISR_ERROR;
+- AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
+ adapter->work_event |= ATL1C_WORK_EVENT_RESET;
+ schedule_work(&adapter->common_task);
+- break;
++ return IRQ_HANDLED;
+ }
+
+ if (status & ISR_OVER)
+@@ -2307,7 +2368,6 @@ void atl1c_down(struct atl1c_adapter *adapter)
+ napi_disable(&adapter->napi);
+ atl1c_irq_disable(adapter);
+ atl1c_free_irq(adapter);
+- AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
+ /* reset MAC to disable all RX/TX */
+ atl1c_reset_mac(&adapter->hw);
+ msleep(1);
+@@ -2391,79 +2451,68 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1c_adapter *adapter = netdev_priv(netdev);
+ struct atl1c_hw *hw = &adapter->hw;
+- u32 ctrl;
+- u32 mac_ctrl_data;
+- u32 master_ctrl_data;
++ u32 mac_ctrl_data = 0;
++ u32 master_ctrl_data = 0;
+ u32 wol_ctrl_data = 0;
+- u16 mii_bmsr_data;
+- u16 save_autoneg_advertised;
+- u16 mii_intr_status_data;
++ u16 mii_intr_status_data = 0;
+ u32 wufc = adapter->wol;
+- u32 i;
+ int retval = 0;
+
++ atl1c_disable_l0s_l1(hw);
+ if (netif_running(netdev)) {
+ WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
+ atl1c_down(adapter);
+ }
+ netif_device_detach(netdev);
+- atl1c_disable_l0s_l1(hw);
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
++
++ if (wufc)
++ if (atl1c_phy_power_saving(hw) != 0)
++ dev_dbg(&pdev->dev, "phy power saving failed");
++
++ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
++ AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
++
++ master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
++ mac_ctrl_data &= ~(MAC_CTRL_PRMLEN_MASK << MAC_CTRL_PRMLEN_SHIFT);
++ mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
++ MAC_CTRL_PRMLEN_MASK) <<
++ MAC_CTRL_PRMLEN_SHIFT);
++ mac_ctrl_data &= ~(MAC_CTRL_SPEED_MASK << MAC_CTRL_SPEED_SHIFT);
++ mac_ctrl_data &= ~MAC_CTRL_DUPLX;
++
+ if (wufc) {
+- AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+- master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
+-
+- /* get link status */
+- atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+- atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+- save_autoneg_advertised = hw->autoneg_advertised;
+- hw->autoneg_advertised = ADVERTISED_10baseT_Half;
+- if (atl1c_restart_autoneg(hw) != 0)
+- if (netif_msg_link(adapter))
+- dev_warn(&pdev->dev, "phy autoneg failed\n");
+- hw->phy_configured = false; /* re-init PHY when resume */
+- hw->autoneg_advertised = save_autoneg_advertised;
++ mac_ctrl_data |= MAC_CTRL_RX_EN;
++ if (adapter->link_speed == SPEED_1000 ||
++ adapter->link_speed == SPEED_0) {
++ mac_ctrl_data |= atl1c_mac_speed_1000 <<
++ MAC_CTRL_SPEED_SHIFT;
++ mac_ctrl_data |= MAC_CTRL_DUPLX;
++ } else
++ mac_ctrl_data |= atl1c_mac_speed_10_100 <<
++ MAC_CTRL_SPEED_SHIFT;
++
++ if (adapter->link_duplex == DUPLEX_FULL)
++ mac_ctrl_data |= MAC_CTRL_DUPLX;
++
+ /* turn on magic packet wol */
+ if (wufc & AT_WUFC_MAG)
+- wol_ctrl_data = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
++ wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+ if (wufc & AT_WUFC_LNKC) {
+- for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
+- msleep(100);
+- atl1c_read_phy_reg(hw, MII_BMSR,
+- (u16 *)&mii_bmsr_data);
+- if (mii_bmsr_data & BMSR_LSTATUS)
+- break;
+- }
+- if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
+- if (netif_msg_link(adapter))
+- dev_warn(&pdev->dev,
+- "%s: Link may change"
+- "when suspend\n",
+- atl1c_driver_name);
+ wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
+ /* only link up can wake up */
+ if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
+- if (netif_msg_link(adapter))
+- dev_err(&pdev->dev,
+- "%s: read write phy "
+- "register failed.\n",
+- atl1c_driver_name);
+- goto wol_dis;
++ dev_dbg(&pdev->dev, "%s: read write phy "
++ "register failed.\n",
++ atl1c_driver_name);
+ }
+ }
+ /* clear phy interrupt */
+ atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
+ /* Config MAC Ctrl register */
+- mac_ctrl_data = MAC_CTRL_RX_EN;
+- /* set to 10/100M halt duplex */
+- mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
+- mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
+- MAC_CTRL_PRMLEN_MASK) <<
+- MAC_CTRL_PRMLEN_SHIFT);
+-
+ if (adapter->vlgrp)
+ mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+
+@@ -2471,37 +2520,30 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
+ if (wufc & AT_WUFC_MAG)
+ mac_ctrl_data |= MAC_CTRL_BC_EN;
+
+- if (netif_msg_hw(adapter))
+- dev_dbg(&pdev->dev,
+- "%s: suspend MAC=0x%x\n",
+- atl1c_driver_name, mac_ctrl_data);
++ dev_dbg(&pdev->dev,
++ "%s: suspend MAC=0x%x\n",
++ atl1c_driver_name, mac_ctrl_data);
+ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+ AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
+ AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+
+ /* pcie patch */
+- AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
+- ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
++ device_set_wakeup_enable(&pdev->dev, 1);
+
+- pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+- goto suspend_exit;
++ AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
++ GPHY_CTRL_EXT_RESET);
++ pci_prepare_to_sleep(pdev);
++ } else {
++ AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING);
++ master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS;
++ mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
++ mac_ctrl_data |= MAC_CTRL_DUPLX;
++ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
++ AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
++ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
++ hw->phy_configured = false; /* re-init PHY when resume */
++ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+ }
+-wol_dis:
+-
+- /* WOL disabled */
+- AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+-
+- /* pcie patch */
+- AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
+- ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+-
+- atl1c_phy_disable(hw);
+- hw->phy_configured = false; /* re-init PHY when resume */
+-
+- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+-suspend_exit:
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+@@ -2520,9 +2562,19 @@ static int atl1c_resume(struct pci_dev *pdev)
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
++ atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
++ ATL1C_PCIE_PHY_RESET);
+
+ atl1c_phy_reset(&adapter->hw);
+ atl1c_reset_mac(&adapter->hw);
++ atl1c_phy_init(&adapter->hw);
++
++#if 0
++ AT_READ_REG(&adapter->hw, REG_PM_CTRLSTAT, &pm_data);
++ pm_data &= ~PM_CTRLSTAT_PME_EN;
++ AT_WRITE_REG(&adapter->hw, REG_PM_CTRLSTAT, pm_data);
++#endif
++
+ netif_device_attach(netdev);
+ if (netif_running(netdev))
+ atl1c_up(adapter);
+@@ -2558,7 +2610,7 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
+ pci_set_drvdata(pdev, netdev);
+
+ netdev->irq = pdev->irq;
+- netdev_attach_ops(netdev, &atl1c_netdev_ops);
++ netdev->netdev_ops = &atl1c_netdev_ops;
+ netdev->watchdog_timeo = AT_TX_WATCHDOG;
+ atl1c_set_ethtool_ops(netdev);
+
+--
+1.7.0.4
+