aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNick Kossifidis <mick@madwifi-project.org>2009-08-09 20:29:02 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:56 -0400
commitedd7fc7003f31da48d06e215a93ea966a22c2a03 (patch)
tree5627da2c85e9a5e28ec047c3914cdf75425187c9 /drivers
parentd1cb0bdac180a4afdd3c001acb2618d2a62d9abe (diff)
ath5k: Wakeup fixes
* Don't put chip to full sleep because there are problems during wakeup. Instead hold MAC/Baseband on warm reset state via a new function ath5k_hw_on_hold. * Minor cleanups Signed-off-by: Nick Kossifidis <mickflemm@gmail.com> Tested-by: Ben Greear <greearb@candelatech.com> Tested-by: Johannes Stezenbach <js@sig21.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c44
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c155
4 files changed, 140 insertions, 62 deletions
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 91375113916b..1047a6cb1d92 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1157,6 +1157,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc);
1157 1157
1158/* Reset Functions */ 1158/* Reset Functions */
1159extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); 1159extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
1160extern int ath5k_hw_on_hold(struct ath5k_hw *ah);
1160extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel); 1161extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
1161/* Power management functions */ 1162/* Power management functions */
1162extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); 1163extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 626306592cf8..238eeb7e166e 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
145 goto err_free; 145 goto err_free;
146 146
147 /* Bring device out of sleep and reset it's units */ 147 /* Bring device out of sleep and reset it's units */
148 ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true); 148 ret = ath5k_hw_nic_wakeup(ah, 0, true);
149 if (ret) 149 if (ret)
150 goto err_free; 150 goto err_free;
151 151
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 5d5028538ac2..0370cba8356c 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2446,27 +2446,29 @@ ath5k_stop_hw(struct ath5k_softc *sc)
2446 ret = ath5k_stop_locked(sc); 2446 ret = ath5k_stop_locked(sc);
2447 if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { 2447 if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
2448 /* 2448 /*
2449 * Set the chip in full sleep mode. Note that we are 2449 * Don't set the card in full sleep mode!
2450 * careful to do this only when bringing the interface 2450 *
2451 * completely to a stop. When the chip is in this state 2451 * a) When the device is in this state it must be carefully
2452 * it must be carefully woken up or references to 2452 * woken up or references to registers in the PCI clock
2453 * registers in the PCI clock domain may freeze the bus 2453 * domain may freeze the bus (and system). This varies
2454 * (and system). This varies by chip and is mostly an 2454 * by chip and is mostly an issue with newer parts
2455 * issue with newer parts that go to sleep more quickly. 2455 * (madwifi sources mentioned srev >= 0x78) that go to
2456 */ 2456 * sleep more quickly.
2457 if (sc->ah->ah_mac_srev >= 0x78) { 2457 *
2458 /* 2458 * b) On older chips full sleep results a weird behaviour
2459 * XXX 2459 * during wakeup. I tested various cards with srev < 0x78
2460 * don't put newer MAC revisions > 7.8 to sleep because 2460 * and they don't wake up after module reload, a second
2461 * of the above mentioned problems 2461 * module reload is needed to bring the card up again.
2462 */ 2462 *
2463 ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " 2463 * Until we figure out what's going on don't enable
2464 "not putting device to sleep\n"); 2464 * full chip reset on any chip (this is what Legacy HAL
2465 } else { 2465 * and Sam's HAL do anyway). Instead Perform a full reset
2466 ATH5K_DBG(sc, ATH5K_DEBUG_RESET, 2466 * on the device (same as initial state after attach) and
2467 "putting device to full sleep\n"); 2467 * leave it idle (keep MAC/BB on warm reset) */
2468 ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); 2468 ret = ath5k_hw_on_hold(sc->ah);
2469 } 2469
2470 ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
2471 "putting device to sleep\n");
2470 } 2472 }
2471 ath5k_txbuf_free(sc, sc->bbuf); 2473 ath5k_txbuf_free(sc, sc->bbuf);
2472 2474
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 86733fdb4774..34e13c700849 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
258 if (!set_chip) 258 if (!set_chip)
259 goto commit; 259 goto commit;
260 260
261 /* Preserve sleep duration */
262 data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL); 261 data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
262
263 /* If card is down we 'll get 0xffff... so we
264 * need to clean this up before we write the register
265 */
263 if (data & 0xffc00000) 266 if (data & 0xffc00000)
264 data = 0; 267 data = 0;
265 else 268 else
266 data = data & 0xfffcffff; 269 /* Preserve sleep duration etc */
270 data = data & ~AR5K_SLEEP_CTL_SLE;
267 271
268 ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); 272 ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
273 AR5K_SLEEP_CTL);
269 udelay(15); 274 udelay(15);
270 275
271 for (i = 50; i > 0; i--) { 276 for (i = 200; i > 0; i--) {
272 /* Check if the chip did wake up */ 277 /* Check if the chip did wake up */
273 if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & 278 if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
274 AR5K_PCICFG_SPWR_DN) == 0) 279 AR5K_PCICFG_SPWR_DN) == 0)
275 break; 280 break;
276 281
277 /* Wait a bit and retry */ 282 /* Wait a bit and retry */
278 udelay(200); 283 udelay(50);
279 ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL); 284 ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
285 AR5K_SLEEP_CTL);
280 } 286 }
281 287
282 /* Fail if the chip didn't wake up */ 288 /* Fail if the chip didn't wake up */
283 if (i <= 0) 289 if (i == 0)
284 return -EIO; 290 return -EIO;
285 291
286 break; 292 break;
@@ -296,6 +302,64 @@ commit:
296} 302}
297 303
298/* 304/*
305 * Put device on hold
306 *
307 * Put MAC and Baseband on warm reset and
308 * keep that state (don't clean sleep control
309 * register). After this MAC and Baseband are
310 * disabled and a full reset is needed to come
311 * back. This way we save as much power as possible
312 * without puting the card on full sleep.
313 */
314int ath5k_hw_on_hold(struct ath5k_hw *ah)
315{
316 struct pci_dev *pdev = ah->ah_sc->pdev;
317 u32 bus_flags;
318 int ret;
319
320 /* Make sure device is awake */
321 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
322 if (ret) {
323 ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
324 return ret;
325 }
326
327 /*
328 * Put chipset on warm reset...
329 *
330 * Note: puting PCI core on warm reset on PCI-E cards
331 * results card to hang and always return 0xffff... so
332 * we ingore that flag for PCI-E cards. On PCI cards
333 * this flag gets cleared after 64 PCI clocks.
334 */
335 bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
336
337 if (ah->ah_version == AR5K_AR5210) {
338 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
339 AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
340 AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
341 mdelay(2);
342 } else {
343 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
344 AR5K_RESET_CTL_BASEBAND | bus_flags);
345 }
346
347 if (ret) {
348 ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");
349 return -EIO;
350 }
351
352 /* ...wakeup again!*/
353 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
354 if (ret) {
355 ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");
356 return ret;
357 }
358
359 return ret;
360}
361
362/*
299 * Bring up MAC + PHY Chips and program PLL 363 * Bring up MAC + PHY Chips and program PLL
300 * TODO: Half/Quarter rate support 364 * TODO: Half/Quarter rate support
301 */ 365 */
@@ -318,6 +382,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
318 return ret; 382 return ret;
319 } 383 }
320 384
385 /*
386 * Put chipset on warm reset...
387 *
388 * Note: puting PCI core on warm reset on PCI-E cards
389 * results card to hang and always return 0xffff... so
390 * we ingore that flag for PCI-E cards. On PCI cards
391 * this flag gets cleared after 64 PCI clocks.
392 */
393 bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
394
395 if (ah->ah_version == AR5K_AR5210) {
396 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
397 AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
398 AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
399 mdelay(2);
400 } else {
401 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
402 AR5K_RESET_CTL_BASEBAND | bus_flags);
403 }
404
405 if (ret) {
406 ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
407 return -EIO;
408 }
409
410 /* ...wakeup again!...*/
411 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
412 if (ret) {
413 ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
414 return ret;
415 }
416
417 /* ...clear reset control register and pull device out of
418 * warm reset */
419 if (ath5k_hw_nic_reset(ah, 0)) {
420 ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
421 return -EIO;
422 }
423
424 /* On initialization skip PLL programming since we don't have
425 * a channel / mode set yet */
426 if (initial)
427 return 0;
428
321 if (ah->ah_version != AR5K_AR5210) { 429 if (ah->ah_version != AR5K_AR5210) {
322 /* 430 /*
323 * Get channel mode flags 431 * Get channel mode flags
@@ -383,39 +491,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
383 AR5K_PHY_TURBO); 491 AR5K_PHY_TURBO);
384 } 492 }
385 493
386 /* reseting PCI on PCI-E cards results card to hang
387 * and always return 0xffff... so we ingore that flag
388 * for PCI-E cards */
389 bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
390
391 /* Reset chipset */
392 if (ah->ah_version == AR5K_AR5210) {
393 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
394 AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
395 AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
396 mdelay(2);
397 } else {
398 ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
399 AR5K_RESET_CTL_BASEBAND | bus_flags);
400 }
401 if (ret) {
402 ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
403 return -EIO;
404 }
405
406 /* ...wakeup again!*/
407 ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
408 if (ret) {
409 ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
410 return ret;
411 }
412
413 /* ...final warm reset */
414 if (ath5k_hw_nic_reset(ah, 0)) {
415 ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
416 return -EIO;
417 }
418
419 if (ah->ah_version != AR5K_AR5210) { 494 if (ah->ah_version != AR5K_AR5210) {
420 495
421 /* ...update PLL if needed */ 496 /* ...update PLL if needed */