diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/reset.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/reset.c | 155 |
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 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 | */ | ||
314 | int 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 */ |