aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2011-07-29 09:59:08 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-01 13:46:46 -0400
commitd4930086bdd0c08a8b3a4d66a9c702297cb74a99 (patch)
tree8834a291d6f1ad0779814f9e55a4f391b98e6f00 /drivers
parent84404623da45aac04595a8f5760a58df0e955d87 (diff)
ath9k: skip ->config_pci_powersave() if PCIe port has ASPM disabled
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> Cc: stable@kernel.org # 2.6.35+ Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-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 9ff7c30573b8..44d9d8d56490 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 8efdec247c02..ad2bb2bf4e8a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -519,11 +519,7 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
519 int restore, 519 int restore,
520 int power_off) 520 int power_off)
521{ 521{
522 if (ah->is_pciexpress != true) 522 if (ah->is_pciexpress != true || ah->aspm_enabled != true)
523 return;
524
525 /* Do not touch SerDes registers */
526 if (ah->config.pcie_powersave_enable == 2)
527 return; 523 return;
528 524
529 /* Nothing to do on restore for 11N */ 525 /* 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 8006ce0c7357..8dcefe74f4c3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -318,6 +318,14 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
318 REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); 318 REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
319} 319}
320 320
321static void ath9k_hw_aspm_init(struct ath_hw *ah)
322{
323 struct ath_common *common = ath9k_hw_common(ah);
324
325 if (common->bus_ops->aspm_init)
326 common->bus_ops->aspm_init(common);
327}
328
321/* This should work for all families including legacy */ 329/* This should work for all families including legacy */
322static bool ath9k_hw_chip_test(struct ath_hw *ah) 330static bool ath9k_hw_chip_test(struct ath_hw *ah)
323{ 331{
@@ -378,7 +386,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
378 ah->config.additional_swba_backoff = 0; 386 ah->config.additional_swba_backoff = 0;
379 ah->config.ack_6mb = 0x0; 387 ah->config.ack_6mb = 0x0;
380 ah->config.cwm_ignore_extcca = 0; 388 ah->config.cwm_ignore_extcca = 0;
381 ah->config.pcie_powersave_enable = 0;
382 ah->config.pcie_clock_req = 0; 389 ah->config.pcie_clock_req = 0;
383 ah->config.pcie_waen = 0; 390 ah->config.pcie_waen = 0;
384 ah->config.analog_shiftreg = 1; 391 ah->config.analog_shiftreg = 1;
@@ -598,7 +605,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
598 605
599 606
600 if (ah->is_pciexpress) 607 if (ah->is_pciexpress)
601 ath9k_hw_configpcipowersave(ah, 0, 0); 608 ath9k_hw_aspm_init(ah);
602 else 609 else
603 ath9k_hw_disablepcie(ah); 610 ath9k_hw_disablepcie(ah);
604 611
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 6acd0f975ae1..c79889036ec4 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -219,7 +219,6 @@ struct ath9k_ops_config {
219 int additional_swba_backoff; 219 int additional_swba_backoff;
220 int ack_6mb; 220 int ack_6mb;
221 u32 cwm_ignore_extcca; 221 u32 cwm_ignore_extcca;
222 u8 pcie_powersave_enable;
223 bool pcieSerDesWrite; 222 bool pcieSerDesWrite;
224 u8 pcie_clock_req; 223 u8 pcie_clock_req;
225 u32 pcie_waen; 224 u32 pcie_waen;
@@ -673,6 +672,7 @@ struct ath_hw {
673 672
674 bool sw_mgmt_crypto; 673 bool sw_mgmt_crypto;
675 bool is_pciexpress; 674 bool is_pciexpress;
675 bool aspm_enabled;
676 bool is_monitoring; 676 bool is_monitoring;
677 bool need_an_top2_fixup; 677 bool need_an_top2_fixup;
678 u16 tx_trig_level; 678 u16 tx_trig_level;
@@ -874,6 +874,7 @@ struct ath_bus_ops {
874 bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); 874 bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
875 void (*bt_coex_prep)(struct ath_common *common); 875 void (*bt_coex_prep)(struct ath_common *common);
876 void (*extn_synch_en)(struct ath_common *common); 876 void (*extn_synch_en)(struct ath_common *common);
877 void (*aspm_init)(struct ath_common *common);
877}; 878};
878 879
879static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) 880static 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 3bad0b2cf9a3..be4ea1329813 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)