diff options
author | Huang, Xiong <xiong@qca.qualcomm.com> | 2012-04-18 22:01:29 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-19 20:14:20 -0400 |
commit | ebe22ed960024385d935620910c1dd9d2c36bf23 (patch) | |
tree | b71465aaa9c58c9befaca23ef8c10c89d3086fd3 | |
parent | 024e1e4dcde98eff0fa5bf2881e4b304c147bd86 (diff) |
atl1c: refine atl1c_pcie_patch
bit PCIE_PHYMISC_FORCE_RCV_DET is only for l1c&l2c to fix WoL issue,
other chips set bit5 of REG_MASTER_CTRL --- this way could save more
power than the former, and the bit should be kept all time.
l2cb 1.x has special setting for L0S/L1
l2cb 1.x & l1d 1.x should clear Vendor Message on some platforms,
otherwise it will cause the root complex hang.
Signed-off-by: xiong <xiong@qca.qualcomm.com>
Tested-by: Liu David <dwliu@qca.qualcomm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_hw.h | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 49 |
2 files changed, 48 insertions, 18 deletions
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h index 5e49ea28d33b..59051e71068f 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.h @@ -96,17 +96,24 @@ int atl1c_phy_power_saving(struct atl1c_hw *hw); #define PCIE_DEV_MISC_SERDES_SEL_DIN 0x10 #define REG_PCIE_PHYMISC 0x1000 -#define PCIE_PHYMISC_FORCE_RCV_DET 0x4 +#define PCIE_PHYMISC_FORCE_RCV_DET BIT(2) +#define PCIE_PHYMISC_NFTS_MASK 0xFFUL +#define PCIE_PHYMISC_NFTS_SHIFT 16 #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 PCIE_PHYMISC2_L0S_TH_MASK 0x3UL +#define PCIE_PHYMISC2_L0S_TH_SHIFT 18 +#define L2CB1_PCIE_PHYMISC2_L0S_TH 3 +#define PCIE_PHYMISC2_CDR_BW_MASK 0x3UL +#define PCIE_PHYMISC2_CDR_BW_SHIFT 16 +#define L2CB1_PCIE_PHYMISC2_CDR_BW 3 #define REG_TWSI_DEBUG 0x1108 #define TWSI_DEBUG_DEV_EXIST 0x20000000 +#define REG_DMA_DBG 0x1114 +#define DMA_DBG_VENDOR_MSG BIT(0) + #define REG_EEPROM_CTRL 0x12C0 #define EEPROM_CTRL_DATA_HI_MASK 0xFFFF #define EEPROM_CTRL_DATA_HI_SHIFT 0 diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 47fe6adf0f45..17b91dbf5e15 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -87,20 +87,37 @@ static void atl1c_pcie_patch(struct atl1c_hw *hw) mst_data &= ~MASTER_CTRL_CLK_SEL_DIS; AT_WRITE_REG(hw, REG_MASTER_CTRL, mst_data); - AT_READ_REG(hw, REG_PCIE_PHYMISC, &data); - data |= PCIE_PHYMISC_FORCE_RCV_DET; - AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data); - + /* WoL/PCIE related settings */ + if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) { + AT_READ_REG(hw, REG_PCIE_PHYMISC, &data); + data |= PCIE_PHYMISC_FORCE_RCV_DET; + AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data); + } else { /* new dev set bit5 of MASTER */ + if (!(mst_data & MASTER_CTRL_WAKEN_25M)) + AT_WRITE_REG(hw, REG_MASTER_CTRL, + mst_data | MASTER_CTRL_WAKEN_25M); + } + /* aspm/PCIE setting only for l2cb 1.0 */ 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; + data = FIELD_SETX(data, PCIE_PHYMISC2_CDR_BW, + L2CB1_PCIE_PHYMISC2_CDR_BW); + data = FIELD_SETX(data, PCIE_PHYMISC2_L0S_TH, + L2CB1_PCIE_PHYMISC2_L0S_TH); AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data); + /* extend L1 sync timer */ + AT_READ_REG(hw, REG_LINK_CTRL, &data); + data |= LINK_CTRL_EXT_SYNC; + AT_WRITE_REG(hw, REG_LINK_CTRL, data); + } + /* l2cb 1.x & l1d 1.x */ + if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d) { + AT_READ_REG(hw, REG_PM_CTRL, &data); + data |= PM_CTRL_L0S_BUFSRX_EN; + AT_WRITE_REG(hw, REG_PM_CTRL, data); + /* clear vendor msg */ + AT_READ_REG(hw, REG_DMA_DBG, &data); + AT_WRITE_REG(hw, REG_DMA_DBG, data & ~DMA_DBG_VENDOR_MSG); } } @@ -1181,8 +1198,8 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) */ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); master_ctrl_data |= MASTER_CTRL_OOB_DIS; - AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST) - & 0xFFFF)); + AT_WRITE_REG(hw, REG_MASTER_CTRL, + master_ctrl_data | MASTER_CTRL_SOFT_RST); AT_WRITE_FLUSH(hw); msleep(10); @@ -1194,6 +1211,8 @@ static int atl1c_reset_mac(struct atl1c_hw *hw) " disabled for 10ms second\n"); return -1; } + AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data); + return 0; } @@ -1338,6 +1357,10 @@ static int atl1c_configure(struct atl1c_adapter *adapter) u32 intr_modrt_data; u32 data; + AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data); + master_ctrl_data &= ~(MASTER_CTRL_TX_ITIMER_EN | + MASTER_CTRL_RX_ITIMER_EN | + MASTER_CTRL_INT_RDCLR); /* clear interrupt status */ AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF); /* Clear any WOL status */ |