From patchwork Mon Aug 23 17:04:15 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 62497 X-Patchwork-Delegate: stefan.bader@canonical.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id F076DB6F07 for ; Tue, 24 Aug 2010 03:04:34 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.69) (envelope-from ) id 1OnaRb-0001D1-OQ; Mon, 23 Aug 2010 18:04:23 +0100 Received: from mail.tpi.com ([70.99.223.143]) by chlorine.canonical.com with esmtp (Exim 4.69) (envelope-from ) id 1OnaRY-0001Af-NT for kernel-team@lists.ubuntu.com; Mon, 23 Aug 2010 18:04:21 +0100 Received: from [10.0.2.5] (unknown [10.0.2.5]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by mail.tpi.com (Postfix) with ESMTP id B6DFB25BD33; Mon, 23 Aug 2010 10:03:42 -0700 (PDT) Message-ID: <4C72AA0F.6080603@canonical.com> Date: Mon, 23 Aug 2010 11:04:15 -0600 From: Tim Gardner User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.11) Gecko/20100713 Thunderbird/3.0.6 MIME-Version: 1.0 To: Stefan Bader Subject: Lucid LBM pull request. LP614426 Cc: Kernel team list X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.9 Precedence: list Reply-To: tim.gardner@canonical.com List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com *sigh* It seems that compat-wireless-2.6.35 doesn't contain a sufficiently advanced atl1c. So, in order to avoid a real mess with extra packages and 'Conflicts:' and whatnot, I've simply implemented the patch infrastructure to update the atl1c driver in the compat-wireless-2.6.35 sources. This should allow for the update of compat-wireless-2.6.35 from stable without losing the backport of atl1c 1.0.1.0-NAPI from 2.6.36-rc2. rtg Acked-by: Stefan Bader Acked-by: Brad Figg diff --git a/debian/rules.d/2-binary-arch.mk b/debian/rules.d/2-binary-arch.mk index f8350d8..37739a5 100644 --- a/debian/rules.d/2-binary-arch.mk +++ b/debian/rules.d/2-binary-arch.mk @@ -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 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 --- ...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 diff --git a/debian/patches/0001-UBUNTU-Update-atl1c-to-1.0.1.0-NAPI-from-2.6.36-rc2.patch b/debian/patches/0001-UBUNTU-Update-atl1c-to-1.0.1.0-NAPI-from-2.6.36-rc2.patch new file mode 100644 index 0000000..0563c92 --- /dev/null +++ b/debian/patches/0001-UBUNTU-Update-atl1c-to-1.0.1.0-NAPI-from-2.6.36-rc2.patch @@ -0,0 +1,1033 @@ +From 642a3786bfe28a4cb38bd5e29c378c1e209448c0 Mon Sep 17 00:00:00 2001 +From: Tim Gardner +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 +--- + .../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 +