ath9k_hw: Update the PCI WAR register

This patch updates the PCI power save handling
code, fixing ASPM hangs and handling device state D3
properly.

The WAR register is programmed with the correct
values now.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Sujith 2010-06-01 15:14:09 +05:30 committed by John W. Linville
parent a55f858852
commit 15ae733b25
2 changed files with 62 additions and 30 deletions

View File

@ -436,55 +436,84 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
}
udelay(1000);
}
/* set bit 19 to allow forcing of pcie core into L1 state */
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
if (power_off) {
/* clear bit 19 to disable L1 */
REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
/* Several PCIe massages to ensure proper behaviour */
val = REG_READ(ah, AR_WA);
/*
* Set PCIe workaround bits
* In AR9280 and AR9285, bit 14 in WA register (disable L1)
* should only be set when device enters D3 and be
* cleared when device comes back to D0.
*/
if (ah->config.pcie_waen) {
if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
val |= AR_WA_D3_L1_DISABLE;
} else {
if (((AR_SREV_9285(ah) ||
AR_SREV_9271(ah) ||
AR_SREV_9287(ah)) &&
(AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
(AR_SREV_9280(ah) &&
(AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
val |= AR_WA_D3_L1_DISABLE;
}
}
if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
/*
* Disable bit 6 and 7 before entering D3 to
* prevent system hang.
*/
val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
}
if (AR_SREV_9285E_20(ah))
val |= AR_WA_BIT23;
REG_WRITE(ah, AR_WA, val);
} else {
if (ah->config.pcie_waen) {
val = ah->config.pcie_waen;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
} else {
if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
if (AR_SREV_9285(ah) ||
AR_SREV_9271(ah) ||
AR_SREV_9287(ah)) {
val = AR9285_WA_DEFAULT;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
} else if (AR_SREV_9280(ah)) {
}
else if (AR_SREV_9280(ah)) {
/*
* On AR9280 chips bit 22 of 0x4004 needs to be
* set otherwise card may disappear.
* For AR9280 chips, bit 22 of 0x4004
* needs to be set.
*/
val = AR9280_WA_DEFAULT;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
} else
} else {
val = AR_WA_DEFAULT;
}
REG_WRITE(ah, AR_WA, val);
}
if (power_off) {
/*
* Set PCIe workaround bits
* bit 14 in WA register (disable L1) should only
* be set when device enters D3 and be cleared
* when device comes back to D0.
*/
if (ah->config.pcie_waen) {
if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
} else {
if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
AR_SREV_9287(ah)) &&
(AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
(AR_SREV_9280(ah) &&
(AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
}
}
/* WAR for ASPM system hang */
if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
val |= (AR_WA_BIT6 | AR_WA_BIT7);
}
if (AR_SREV_9285E_20(ah))
val |= AR_WA_BIT23;
REG_WRITE(ah, AR_WA, val);
/* set bit 19 to allow forcing of pcie core into L1 state */
REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
}
}

View File

@ -700,6 +700,9 @@
#define AR_RC_HOSTIF 0x00000100
#define AR_WA 0x4004
#define AR_WA_BIT6 (1 << 6)
#define AR_WA_BIT7 (1 << 7)
#define AR_WA_BIT23 (1 << 23)
#define AR_WA_D3_L1_DISABLE (1 << 14)
#define AR9285_WA_DEFAULT 0x004a050b
#define AR9280_WA_DEFAULT 0x0040073b