]> git.proxmox.com Git - pve-kernel-2.6.32.git/commitdiff
atl1c: Add support for Atheros AR8152 and AR8152
authorDietmar Maurer <dietmar@proxmox.com>
Fri, 15 Jun 2012 10:45:26 +0000 (12:45 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Fri, 15 Jun 2012 12:59:30 +0000 (14:59 +0200)
Makefile
atl1c-Add-missing-PCI-device-ID.patch [new file with mode: 0644]
atl1c-Add-support-for-Atheros-AR8151v2.patch [new file with mode: 0644]
atl1c-Add-support-for-Atheros-AR8152-and-AR8152.patch [new file with mode: 0644]
changelog.Debian

index 8966b12e5f44e9632b985add5892edf761dfb0a0..f6d1ad6684140a738e6ad0210695260a3069bcce 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 RELEASE=2.1
 
 KERNEL_VER=2.6.32
-PKGREL=69
+PKGREL=70
 # also include firmware of previous versrion into 
 # the fw package:  fwlist-2.6.32-PREV-pve
 KREL=13
@@ -134,6 +134,10 @@ ${KERNEL_SRC}/README: ${KERNEL_SRC}.org/README
        cd ${KERNEL_SRC}; patch -p1 <../bridge-patch.diff
        cd ${KERNEL_SRC}; patch -p1 <../fix-aspm-policy.patch
        cd ${KERNEL_SRC}; patch -p1 <../optimize-cfq-parameters.patch
+       # fix atheros atl1c driver (backports from 3.0.34)
+       cd ${KERNEL_SRC}; patch -p1 <../atl1c-Add-support-for-Atheros-AR8152-and-AR8152.patch
+       cd ${KERNEL_SRC}; patch -p1 <../atl1c-Add-support-for-Atheros-AR8151v2.patch
+       cd ${KERNEL_SRC}; patch -p1 <../atl1c-Add-missing-PCI-device-ID.patch
        sed -i ${KERNEL_SRC}/Makefile -e 's/^EXTRAVERSION.*$$/EXTRAVERSION=${EXTRAVERSION}/'
        touch $@
 
diff --git a/atl1c-Add-missing-PCI-device-ID.patch b/atl1c-Add-missing-PCI-device-ID.patch
new file mode 100644 (file)
index 0000000..13b27c8
--- /dev/null
@@ -0,0 +1,30 @@
+From 94dde7e451fa70749fa68df3d70e4b20debe96a6 Mon Sep 17 00:00:00 2001
+From: Chuck Ebbert <cebbert@redhat.com>
+Date: Wed, 2 Feb 2011 15:02:08 -0800
+Subject: [PATCH] atl1c: Add missing PCI device ID
+
+Commit 8f574b35f22fbb9b5e5f1d11ad6b55b6f35f4533 ("atl1c: Add AR8151 v2
+support and change L0s/L1 routine") added support for a new adapter
+but failed to add it to the PCI device table.
+
+Signed-Off-By: Chuck Ebbert <cebbert@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/atl1c/atl1c_main.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
+index a699bbf..3824382 100644
+--- a/drivers/net/atl1c/atl1c_main.c
++++ b/drivers/net/atl1c/atl1c_main.c
+@@ -48,6 +48,7 @@ static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
++      {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D_2_0)},
+       /* required last entry */
+       { 0 }
+ };
+-- 
+1.7.7.6
+
diff --git a/atl1c-Add-support-for-Atheros-AR8151v2.patch b/atl1c-Add-support-for-Atheros-AR8151v2.patch
new file mode 100644 (file)
index 0000000..e29ad39
--- /dev/null
@@ -0,0 +1,1038 @@
+From 8f574b35f22fbb9b5e5f1d11ad6b55b6f35f4533 Mon Sep 17 00:00:00 2001
+From: Jie Yang <Jie.Yang@atheros.com>
+Date: Tue, 1 Jun 2010 00:28:12 -0700
+Subject: [PATCH] atl1c: Add AR8151 v2 support and change L0s/L1 routine
+
+Add AR8151 v2.0 Gigabit 1000 support
+Change jumbo frame size to 6K
+Update L0s/L1 rountine
+        when link speed is 100M or 1G, set L1 link timer to 4 for l1d_2 and l2c_b2
+        set L1 link timer to 7 for l2c_b, set L1 link timer to 0xF for others.
+Update atl1c_suspend routine
+       just refactory the function, add atl1c_phy_power_saving routine,
+       when Wake On Lan enable, this func will be called to save power,
+       it will reautoneg PHY to 10/100M speed depend on the link
+       partners link capability.
+Update atl1c_configure_des_ring
+        do not use l2c_b default SRAM configuration.
+
+Signed-off-by: Jie Yang <Jie.Yang@atheros.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ 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 |  348 +++++++++++++++++++++++-----------------
+ 4 files changed, 345 insertions(+), 168 deletions(-)
+
+diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
+index 84ae905..52abbbd 100644
+--- a/drivers/net/atl1c/atl1c.h
++++ b/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/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
+index f1389d6..d8501f0 100644
+--- a/drivers/net/atl1c/atl1c_hw.c
++++ b/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, &ltssm_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/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
+index 1eeb3ed..3dd6759 100644
+--- a/drivers/net/atl1c/atl1c_hw.h
++++ b/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/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
+index 1c3c046..c7b8ef5 100644
+--- a/drivers/net/atl1c/atl1c_main.c
++++ b/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,9 +343,10 @@ 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;
+ }
+@@ -476,6 +507,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);
+@@ -613,6 +651,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;
+       }
+@@ -627,9 +668,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;
+@@ -637,12 +676,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;
+ }
+ /*
+@@ -657,6 +696,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;
+@@ -669,7 +710,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;
+@@ -974,6 +1016,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,
+@@ -1017,6 +1060,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);
+ }
+@@ -1029,6 +1089,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;
+@@ -1046,8 +1107,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);
+ }
+@@ -1078,7 +1142,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);
+@@ -1198,21 +1262,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 */
+@@ -1253,42 +1319,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;
+@@ -1297,27 +1360,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;
+@@ -1326,24 +1388,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)
+@@ -1351,8 +1401,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)
+@@ -1391,7 +1442,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;
+       }
+@@ -1409,6 +1461,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);
+@@ -1418,6 +1471,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);
+@@ -1436,6 +1498,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) {
+@@ -1624,11 +1687,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)
+@@ -2303,7 +2364,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);
+@@ -2387,79 +2447,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;
+@@ -2467,37 +2516,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));
+@@ -2516,9 +2558,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);
+-- 
+1.7.6.5
+
diff --git a/atl1c-Add-support-for-Atheros-AR8152-and-AR8152.patch b/atl1c-Add-support-for-Atheros-AR8152-and-AR8152.patch
new file mode 100644 (file)
index 0000000..c22e6e5
--- /dev/null
@@ -0,0 +1,421 @@
+From 496c185c9495629ef1c65387cb2594578393cfe0 Mon Sep 17 00:00:00 2001
+From: "Luis R. Rodriguez" <lrodriguez@atheros.com>
+Date: Tue, 16 Feb 2010 15:16:45 -0800
+Subject: [PATCH] atl1c: Add support for Atheros AR8152 and AR8152
+
+AR8151 is a Gigabit Ethernet device. AR8152 devices are
+Fast Ethernet devices, there are two revisions, a 1.0
+and a 2.0 revision.
+
+This has been tested against these devices:
+
+Driver Model-name      vendor:device   Type
+atl1c  AR8131          1969:1063       Gigabit Ethernet
+atl1c  AR8132          1969:1062       Fast Ethernet
+atl1c  AR8151(v1.0)    1969:1073       Gigabit Ethernet
+atl1c  AR8152(v1.1)    1969:2060       Fast Ethernet
+
+This device has no hardware available yet so it goes untested,
+but it should work:
+
+atl1c  AR8152(v2.0)    1969:2062       Fast Ethernet
+
+Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/atl1c/atl1c.h         |   11 +++-
+ drivers/net/atl1c/atl1c_ethtool.c |    2 +-
+ drivers/net/atl1c/atl1c_hw.c      |   83 +++++++++++++++++++++++----
+ drivers/net/atl1c/atl1c_hw.h      |    5 ++
+ drivers/net/atl1c/atl1c_main.c    |  115 +++++++++++++++++++++++++++++++++---
+ 5 files changed, 191 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
+index efe5435..84ae905 100644
+--- a/drivers/net/atl1c/atl1c.h
++++ b/drivers/net/atl1c/atl1c.h
+@@ -313,6 +313,9 @@ enum atl1c_rss_type {
+ enum atl1c_nic_type {
+       athr_l1c = 0,
+       athr_l2c = 1,
++      athr_l2c_b,
++      athr_l2c_b2,
++      athr_l1d,
+ };
+ enum atl1c_trans_queue {
+@@ -426,8 +429,12 @@ struct atl1c_hw {
+ #define ATL1C_ASPM_L1_SUPPORT         0x0100
+ #define ATL1C_ASPM_CTRL_MON           0x0200
+ #define ATL1C_HIB_DISABLE             0x0400
+-#define ATL1C_LINK_CAP_1000M          0x0800
+-#define ATL1C_FPGA_VERSION            0x8000
++#define ATL1C_APS_MODE_ENABLE           0x0800
++#define ATL1C_LINK_EXT_SYNC             0x1000
++#define ATL1C_CLK_GATING_EN             0x2000
++#define ATL1C_FPGA_VERSION              0x8000
++      u16 link_cap_flags;
++#define ATL1C_LINK_CAP_1000M          0x0001
+       u16 cmb_tpd;
+       u16 cmb_rrd;
+       u16 cmb_rx_timer; /* 2us resolution */
+diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
+index 9b1e0ea..61a0f2f 100644
+--- a/drivers/net/atl1c/atl1c_ethtool.c
++++ b/drivers/net/atl1c/atl1c_ethtool.c
+@@ -37,7 +37,7 @@ static int atl1c_get_settings(struct net_device *netdev,
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_Autoneg       |
+                          SUPPORTED_TP);
+-      if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
++      if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M)
+               ecmd->supported |= SUPPORTED_1000baseT_Full;
+       ecmd->advertising = ADVERTISED_TP;
+diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
+index 3e69b94..f1389d6 100644
+--- a/drivers/net/atl1c/atl1c_hw.c
++++ b/drivers/net/atl1c/atl1c_hw.c
+@@ -70,17 +70,39 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+       u32 otp_ctrl_data;
+       u32 twsi_ctrl_data;
+       u8  eth_addr[ETH_ALEN];
++      u16 phy_data;
++      bool raise_vol = false;
+       /* init */
+       addr[0] = addr[1] = 0;
+       AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
+       if (atl1c_check_eeprom_exist(hw)) {
+-              /* Enable OTP CLK */
+-              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);
++              if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
++                      /* Enable OTP CLK */
++                      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);
++                      }
++              }
++
++              if (hw->nic_type == athr_l2c_b ||
++                  hw->nic_type == athr_l2c_b2 ||
++                  hw->nic_type == athr_l1d) {
++                      atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
++                      if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
++                              goto out;
++                      phy_data &= 0xFF7F;
++                      atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
++
++                      atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
++                      if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
++                              goto out;
++                      phy_data |= 0x8;
++                      atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
++                      udelay(20);
++                      raise_vol = true;
+               }
+               AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
+@@ -96,11 +118,31 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+                       return -1;
+       }
+       /* Disable OTP_CLK */
+-      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);
++      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);
++              }
++      }
++      if (raise_vol) {
++              if (hw->nic_type == athr_l2c_b ||
++                  hw->nic_type == athr_l2c_b2 ||
++                  hw->nic_type == athr_l1d) {
++                      atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
++                      if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
++                              goto out;
++                      phy_data |= 0x80;
++                      atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
++
++                      atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
++                      if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
++                              goto out;
++                      phy_data &= 0xFFF7;
++                      atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
++                      udelay(20);
++              }
+       }
+       /* maybe MAC-address is from BIOS */
+@@ -114,6 +156,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+               return 0;
+       }
++out:
+       return -1;
+ }
+@@ -307,7 +350,7 @@ static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
+               mii_adv_data |= ADVERTISE_10HALF  | ADVERTISE_10FULL |
+                               ADVERTISE_100HALF | ADVERTISE_100FULL;
+-      if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
++      if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) {
+               if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
+                       mii_giga_ctrl_data |= ADVERTISE_1000HALF;
+               if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
+@@ -389,6 +432,7 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
+ {
+       struct atl1c_adapter *adapter = hw->adapter;
+       struct pci_dev *pdev = adapter->pdev;
++      u16 phy_data;
+       u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
+       u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
+       int err;
+@@ -404,6 +448,21 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
+       AT_WRITE_FLUSH(hw);
+       msleep(10);
++      if (hw->nic_type == athr_l2c_b) {
++              atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x0A);
++              atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
++              atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xDFFF);
++      }
++
++      if (hw->nic_type == athr_l2c_b ||
++          hw->nic_type == athr_l2c_b2 ||
++          hw->nic_type == athr_l1d) {
++              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 */
+       err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
+       if (err) {
+diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
+index c2c738d..1eeb3ed 100644
+--- a/drivers/net/atl1c/atl1c_hw.h
++++ b/drivers/net/atl1c/atl1c_hw.h
+@@ -57,6 +57,7 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define REG_LINK_CTRL                 0x68
+ #define LINK_CTRL_L0S_EN              0x01
+ #define LINK_CTRL_L1_EN                       0x02
++#define LINK_CTRL_EXT_SYNC            0x80
+ #define REG_VPD_CAP                   0x6C
+ #define VPD_CAP_ID_MASK                 0xff
+@@ -156,6 +157,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define PM_CTRL_PM_REQ_TIMER_SHIFT    20
+ #define PM_CTRL_LCKDET_TIMER_MASK     0x3F
+ #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
+@@ -314,6 +317,8 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
+ #define MAC_CTRL_BC_EN                0x4000000
+ #define MAC_CTRL_DBG                  0x8000000
+ #define MAC_CTRL_SINGLE_PAUSE_EN      0x10000000
++#define MAC_CTRL_HASH_ALG_CRC32               0x20000000
++#define MAC_CTRL_SPEED_MODE_SW                0x40000000
+ /* MAC IPG/IFG Control Register  */
+ #define REG_MAC_IPG_IFG               0x1484
+diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
+index d98095d..3d4c0a5 100644
+--- a/drivers/net/atl1c/atl1c_main.c
++++ b/drivers/net/atl1c/atl1c_main.c
+@@ -21,11 +21,18 @@
+ #include "atl1c.h"
+-#define ATL1C_DRV_VERSION "1.0.0.1-NAPI"
++#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
+ char atl1c_driver_name[] = "atl1c";
+ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
+ #define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
+ #define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063
++#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 L2CB_V10                      0xc0
++#define L2CB_V11                      0xc1
++
+ /*
+  * atl1c_pci_tbl - PCI Device ID Table
+  *
+@@ -38,6 +45,9 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
+ static DEFINE_PCI_DEVICE_TABLE(atl1c_pci_tbl) = {
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
++      {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B)},
++      {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L2C_B2)},
++      {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATHEROS_L1D)},
+       /* required last entry */
+       { 0 }
+ };
+@@ -593,11 +603,18 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
+       case PCI_DEVICE_ID_ATTANSIC_L2C:
+               hw->nic_type = athr_l2c;
+               break;
+-
+       case PCI_DEVICE_ID_ATTANSIC_L1C:
+               hw->nic_type = athr_l1c;
+               break;
+-
++      case PCI_DEVICE_ID_ATHEROS_L2C_B:
++              hw->nic_type = athr_l2c_b;
++              break;
++      case PCI_DEVICE_ID_ATHEROS_L2C_B2:
++              hw->nic_type = athr_l2c_b2;
++              break;
++      case PCI_DEVICE_ID_ATHEROS_L1D:
++              hw->nic_type = athr_l1d;
++              break;
+       default:
+               break;
+       }
+@@ -620,10 +637,13 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
+               hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
+       if (link_ctrl_data & LINK_CTRL_L1_EN)
+               hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
++      if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
++              hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
+-      if (hw->nic_type == athr_l1c) {
++      if (hw->nic_type == athr_l1c ||
++          hw->nic_type == athr_l1d) {
+               hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+-              hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
++              hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
+       }
+       return 0;
+ }
+@@ -1234,21 +1254,92 @@ static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
+ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+ {
+       u32 pm_ctrl_data;
++      u32 link_ctrl_data;
+       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_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;
++
++      if (hw->nic_type == athr_l2c_b ||
++          hw->nic_type == athr_l1d ||
++          hw->nic_type == athr_l2c_b2) {
++              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)
++                              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_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;
++      }
+       if (linkup) {
+-              pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+-              pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
++              pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
++              pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
++              if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
++                      pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
++              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)
++                              if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
++                                      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;
++                      }
++              } else {
++                      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;
++                      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);
+-              pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
+-              pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+       } else {
+               pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+               pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
+@@ -1302,6 +1393,10 @@ 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) {
++              mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
++              mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
++      }
+       AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+ }
+-- 
+1.7.6.5
+
index 18f91bce238ea3867afd2ec38d61119fe3219d27..f1d7870c056f435044c7648fb308553d64b60642 100644 (file)
@@ -1,3 +1,11 @@
+pve-kernel-2.6.32 (2.6.32-70) unstable; urgency=low
+
+  * atl1c: Add support for Atheros AR8152 and AR8152
+
+  * atl1c: Add AR8151 v2 support
+  
+ -- Proxmox Support Team <support@proxmox.com>  Fri, 15 Jun 2012 12:44:36 +0200
+
 pve-kernel-2.6.32 (2.6.32-69) unstable; urgency=low
 
   * update to vzkernel-2.6.32-042stab055.16.src.rpm