aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/reset.c
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/net/wireless/ath/ath5k/reset.c
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/net/wireless/ath/ath5k/reset.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c155
1 files changed, 115 insertions, 40 deletions
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 86733fdb477..34e13c70084 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 */