aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2011-07-29 09:59:08 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-08-15 21:31:33 -0400
commitc82ac94469ab54ca57b05fd85ce709530d44002f (patch)
tree30ce483069f10555147e64234be9eee462a002e5 /drivers/net
parentcbd1db4bb30ca684d811f4b5bf5dc099aa582445 (diff)
ath9k: skip ->config_pci_powersave() if PCIe port has ASPM disabled
commit d4930086bdd0c08a8b3a4d66a9c702297cb74a99 upstream. We receive many bug reports about system hang during suspend/resume when ath9k driver is in use. Adrian Chadd remarked that this problem happens on systems that have ASPM disabled. To do not hit the bug, skip doing ->config_pci_powersave magic if PCIe downstream port device, which ath9k device is connected to, has ASPM disabled. Bug was introduced by: commit 53bc7aa08b48e5cd745f986731cc7dc24eef2a9f Author: Vivek Natarajan <vnatarajan@atheros.com> Date: Mon Apr 5 14:48:04 2010 +0530 ath9k: Add support for newer AR9285 chipsets. Patch should address: https://bugzilla.kernel.org/show_bug.cgi?id=37462 https://bugzilla.kernel.org/show_bug.cgi?id=37082 https://bugzilla.redhat.com/show_bug.cgi?id=697157 however I did not receive confirmation about that, except from Camilo Mesias, whose system stops hang regularly with this patch (but still hangs from time to time, but this is probably some other bug). Tested-by: Camilo Mesias <camilo@mesias.co.uk> Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c27
5 files changed, 40 insertions, 13 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index f344cc2b3d5..c32f9d1b215 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -309,11 +309,7 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
309 u8 i; 309 u8 i;
310 u32 val; 310 u32 val;
311 311
312 if (ah->is_pciexpress != true) 312 if (ah->is_pciexpress != true || ah->aspm_enabled != true)
313 return;
314
315 /* Do not touch SerDes registers */
316 if (ah->config.pcie_powersave_enable == 2)
317 return; 313 return;
318 314
319 /* Nothing to do on restore for 11N */ 315 /* Nothing to do on restore for 11N */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 392bf0f8ff1..7e02fb4b4b5 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -351,11 +351,7 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
351 int restore, 351 int restore,
352 int power_off) 352 int power_off)
353{ 353{
354 if (ah->is_pciexpress != true) 354 if (ah->is_pciexpress != true || ah->aspm_enabled != true)
355 return;
356
357 /* Do not touch SerDes registers */
358 if (ah->config.pcie_powersave_enable == 2)
359 return; 355 return;
360 356
361 /* Nothing to do on restore for 11N */ 357 /* Nothing to do on restore for 11N */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 1be7c8bbef8..03900ca7d99 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -299,6 +299,14 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
299 REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); 299 REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
300} 300}
301 301
302static void ath9k_hw_aspm_init(struct ath_hw *ah)
303{
304 struct ath_common *common = ath9k_hw_common(ah);
305
306 if (common->bus_ops->aspm_init)
307 common->bus_ops->aspm_init(common);
308}
309
302/* This should work for all families including legacy */ 310/* This should work for all families including legacy */
303static bool ath9k_hw_chip_test(struct ath_hw *ah) 311static bool ath9k_hw_chip_test(struct ath_hw *ah)
304{ 312{
@@ -359,7 +367,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
359 ah->config.additional_swba_backoff = 0; 367 ah->config.additional_swba_backoff = 0;
360 ah->config.ack_6mb = 0x0; 368 ah->config.ack_6mb = 0x0;
361 ah->config.cwm_ignore_extcca = 0; 369 ah->config.cwm_ignore_extcca = 0;
362 ah->config.pcie_powersave_enable = 0;
363 ah->config.pcie_clock_req = 0; 370 ah->config.pcie_clock_req = 0;
364 ah->config.pcie_waen = 0; 371 ah->config.pcie_waen = 0;
365 ah->config.analog_shiftreg = 1; 372 ah->config.analog_shiftreg = 1;
@@ -577,7 +584,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
577 584
578 585
579 if (ah->is_pciexpress) 586 if (ah->is_pciexpress)
580 ath9k_hw_configpcipowersave(ah, 0, 0); 587 ath9k_hw_aspm_init(ah);
581 else 588 else
582 ath9k_hw_disablepcie(ah); 589 ath9k_hw_disablepcie(ah);
583 590
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 4b157c53d1a..939cc9d76c2 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -215,7 +215,6 @@ struct ath9k_ops_config {
215 int additional_swba_backoff; 215 int additional_swba_backoff;
216 int ack_6mb; 216 int ack_6mb;
217 u32 cwm_ignore_extcca; 217 u32 cwm_ignore_extcca;
218 u8 pcie_powersave_enable;
219 bool pcieSerDesWrite; 218 bool pcieSerDesWrite;
220 u8 pcie_clock_req; 219 u8 pcie_clock_req;
221 u32 pcie_waen; 220 u32 pcie_waen;
@@ -671,6 +670,7 @@ struct ath_hw {
671 670
672 bool sw_mgmt_crypto; 671 bool sw_mgmt_crypto;
673 bool is_pciexpress; 672 bool is_pciexpress;
673 bool aspm_enabled;
674 bool is_monitoring; 674 bool is_monitoring;
675 bool need_an_top2_fixup; 675 bool need_an_top2_fixup;
676 u16 tx_trig_level; 676 u16 tx_trig_level;
@@ -870,6 +870,7 @@ struct ath_bus_ops {
870 bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); 870 bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
871 void (*bt_coex_prep)(struct ath_common *common); 871 void (*bt_coex_prep)(struct ath_common *common);
872 void (*extn_synch_en)(struct ath_common *common); 872 void (*extn_synch_en)(struct ath_common *common);
873 void (*aspm_init)(struct ath_common *common);
873}; 874};
874 875
875static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) 876static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 3bad0b2cf9a..be4ea132981 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -16,6 +16,7 @@
16 16
17#include <linux/nl80211.h> 17#include <linux/nl80211.h>
18#include <linux/pci.h> 18#include <linux/pci.h>
19#include <linux/pci-aspm.h>
19#include <linux/ath9k_platform.h> 20#include <linux/ath9k_platform.h>
20#include "ath9k.h" 21#include "ath9k.h"
21 22
@@ -115,12 +116,38 @@ static void ath_pci_extn_synch_enable(struct ath_common *common)
115 pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); 116 pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
116} 117}
117 118
119static void ath_pci_aspm_init(struct ath_common *common)
120{
121 struct ath_softc *sc = (struct ath_softc *) common->priv;
122 struct ath_hw *ah = sc->sc_ah;
123 struct pci_dev *pdev = to_pci_dev(sc->dev);
124 struct pci_dev *parent;
125 int pos;
126 u8 aspm;
127
128 if (!pci_is_pcie(pdev))
129 return;
130
131 parent = pdev->bus->self;
132 if (WARN_ON(!parent))
133 return;
134
135 pos = pci_pcie_cap(parent);
136 pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm);
137 if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) {
138 ah->aspm_enabled = true;
139 /* Initialize PCIe PM and SERDES registers. */
140 ath9k_hw_configpcipowersave(ah, 0, 0);
141 }
142}
143
118static const struct ath_bus_ops ath_pci_bus_ops = { 144static const struct ath_bus_ops ath_pci_bus_ops = {
119 .ath_bus_type = ATH_PCI, 145 .ath_bus_type = ATH_PCI,
120 .read_cachesize = ath_pci_read_cachesize, 146 .read_cachesize = ath_pci_read_cachesize,
121 .eeprom_read = ath_pci_eeprom_read, 147 .eeprom_read = ath_pci_eeprom_read,
122 .bt_coex_prep = ath_pci_bt_coex_prep, 148 .bt_coex_prep = ath_pci_bt_coex_prep,
123 .extn_synch_en = ath_pci_extn_synch_enable, 149 .extn_synch_en = ath_pci_extn_synch_enable,
150 .aspm_init = ath_pci_aspm_init,
124}; 151};
125 152
126static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 153static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)