aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-12-24 07:15:41 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-01-13 15:17:05 -0500
commit2d93aee152b1758a94a18fe15d72153ba73b5679 (patch)
tree478c9f9927a38b6e7daae2a23ef8aa8501bc1870 /drivers/net
parent2775613f4ff32f8be2cae42d542b7fbefcafbfbe (diff)
iwlwifi: pcie: enable oscillator for L1 exit
Enabling the oscillator consumes slightly more power (100uA) but allows to make sure that we exit from L1 on time. Not doing so might lead to a PCIe specification violation since we might wake up from L1 at the wrong time. This issue has been identified on 3160 and 7260 only. On older NICs L1 off is not enabled, on newer NICs (7265), the issue is fixed. When the bug occurs the user sees that the NIC has disappeared from the PCI bridge, any access to the device returns 0xff. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=64541 and has been extensively discussed here: http://markmail.org/thread/mfmpzqt3r333n4bo Cc: stable@vger.kernel.org [3.10+] Fixes: 99cd47142399 ("iwlwifi: add 7000 series device configuration") Reported-and-tested-by: wzyboy <wzyboy@wzyboy.org> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h4
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c22
2 files changed, 26 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index d69b0fb0a434..100bd0d79681 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -277,4 +277,8 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
277 277
278/*********************** END TX SCHEDULER *************************************/ 278/*********************** END TX SCHEDULER *************************************/
279 279
280/* Oscillator clock */
281#define OSC_CLK (0xa04068)
282#define OSC_CLK_FORCE_CONTROL (0x8)
283
280#endif /* __iwl_prph_h__ */ 284#endif /* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 16f66c1a23de..f9507807b486 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -178,6 +178,28 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
178 goto out; 178 goto out;
179 } 179 }
180 180
181 if (trans->cfg->host_interrupt_operation_mode) {
182 /*
183 * This is a bit of an abuse - This is needed for 7260 / 3160
184 * only check host_interrupt_operation_mode even if this is
185 * not related to host_interrupt_operation_mode.
186 *
187 * Enable the oscillator to count wake up time for L1 exit. This
188 * consumes slightly more power (100uA) - but allows to be sure
189 * that we wake up from L1 on time.
190 *
191 * This looks weird: read twice the same register, discard the
192 * value, set a bit, and yet again, read that same register
193 * just to discard the value. But that's the way the hardware
194 * seems to like it.
195 */
196 iwl_read_prph(trans, OSC_CLK);
197 iwl_read_prph(trans, OSC_CLK);
198 iwl_set_bits_prph(trans, OSC_CLK, OSC_CLK_FORCE_CONTROL);
199 iwl_read_prph(trans, OSC_CLK);
200 iwl_read_prph(trans, OSC_CLK);
201 }
202
181 /* 203 /*
182 * Enable DMA clock and wait for it to stabilize. 204 * Enable DMA clock and wait for it to stabilize.
183 * 205 *