diff options
author | Nick Kossifidis <mickflemm@gmail.com> | 2010-11-23 13:41:15 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-11-30 13:52:30 -0500 |
commit | d41174fabdae348c6583cf05aeb329da232c342c (patch) | |
tree | 6f1979e64f748c8f6c060c28804424a79f49b0d6 | |
parent | 9320b5c4a7260d9593102f378201d17e3f030739 (diff) |
ath5k: Add new function to stop rx/tx DMA
* Add a new function to stop rx/tx dma and use in when reset starts
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ath5k.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/dma.c | 52 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/reset.c | 13 |
3 files changed, 59 insertions, 9 deletions
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 85ff822c81f4..629a5eebe302 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -1180,8 +1180,9 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); | |||
1180 | int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); | 1180 | int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); |
1181 | enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); | 1181 | enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); |
1182 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); | 1182 | void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); |
1183 | /* Init function */ | 1183 | /* Init/Stop functions */ |
1184 | void ath5k_hw_dma_init(struct ath5k_hw *ah); | 1184 | void ath5k_hw_dma_init(struct ath5k_hw *ah); |
1185 | int ath5k_hw_dma_stop(struct ath5k_hw *ah); | ||
1185 | 1186 | ||
1186 | /* EEPROM access functions */ | 1187 | /* EEPROM access functions */ |
1187 | int ath5k_eeprom_init(struct ath5k_hw *ah); | 1188 | int ath5k_eeprom_init(struct ath5k_hw *ah); |
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index b991b0585090..ca0467e21e56 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c | |||
@@ -126,7 +126,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
126 | 126 | ||
127 | /* Return if queue is declared inactive */ | 127 | /* Return if queue is declared inactive */ |
128 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | 128 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) |
129 | return -EIO; | 129 | return -EINVAL; |
130 | 130 | ||
131 | if (ah->ah_version == AR5K_AR5210) { | 131 | if (ah->ah_version == AR5K_AR5210) { |
132 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); | 132 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); |
@@ -174,7 +174,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
174 | * | 174 | * |
175 | * Stop DMA transmit on a specific hw queue and drain queue so we don't | 175 | * Stop DMA transmit on a specific hw queue and drain queue so we don't |
176 | * have any pending frames. Returns -EBUSY if we still have pending frames, | 176 | * have any pending frames. Returns -EBUSY if we still have pending frames, |
177 | * -EINVAL if queue number is out of range. | 177 | * -EINVAL if queue number is out of range or inactive. |
178 | * | 178 | * |
179 | */ | 179 | */ |
180 | int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | 180 | int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) |
@@ -186,7 +186,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
186 | 186 | ||
187 | /* Return if queue is declared inactive */ | 187 | /* Return if queue is declared inactive */ |
188 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | 188 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) |
189 | return -EIO; | 189 | return -EINVAL; |
190 | 190 | ||
191 | if (ah->ah_version == AR5K_AR5210) { | 191 | if (ah->ah_version == AR5K_AR5210) { |
192 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); | 192 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); |
@@ -733,3 +733,49 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah) | |||
733 | ath5k_hw_set_imr(ah, ah->ah_imr); | 733 | ath5k_hw_set_imr(ah, ah->ah_imr); |
734 | 734 | ||
735 | } | 735 | } |
736 | |||
737 | /** | ||
738 | * ath5k_hw_dma_stop - stop DMA unit | ||
739 | * | ||
740 | * @ah: The &struct ath5k_hw | ||
741 | * | ||
742 | * Stop tx/rx DMA and interrupts. Returns | ||
743 | * -EBUSY if tx or rx dma failed to stop. | ||
744 | * | ||
745 | * XXX: Sometimes DMA unit hangs and we have | ||
746 | * stuck frames on tx queues, only a reset | ||
747 | * can fix that. | ||
748 | */ | ||
749 | int ath5k_hw_dma_stop(struct ath5k_hw *ah) | ||
750 | { | ||
751 | int i, qmax, err; | ||
752 | err = 0; | ||
753 | |||
754 | /* Disable interrupts */ | ||
755 | ath5k_hw_set_imr(ah, 0); | ||
756 | |||
757 | /* Stop rx dma */ | ||
758 | err = ath5k_hw_stop_rx_dma(ah); | ||
759 | if (err) | ||
760 | return err; | ||
761 | |||
762 | /* Clear any pending interrupts | ||
763 | * and disable tx dma */ | ||
764 | if (ah->ah_version != AR5K_AR5210) { | ||
765 | ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); | ||
766 | qmax = AR5K_NUM_TX_QUEUES; | ||
767 | } else { | ||
768 | /* PISR/SISR Not available on 5210 */ | ||
769 | ath5k_hw_reg_read(ah, AR5K_ISR); | ||
770 | qmax = AR5K_NUM_TX_QUEUES_NOQCU; | ||
771 | } | ||
772 | |||
773 | for (i = 0; i < qmax; i++) { | ||
774 | err = ath5k_hw_stop_tx_dma(ah, i); | ||
775 | /* -EINVAL -> queue inactive */ | ||
776 | if (err != -EINVAL) | ||
777 | return err; | ||
778 | } | ||
779 | |||
780 | return err; | ||
781 | } | ||
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 9dd5792780ba..083367712d67 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c | |||
@@ -823,6 +823,14 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
823 | mode = 0; | 823 | mode = 0; |
824 | 824 | ||
825 | /* | 825 | /* |
826 | * Stop DMA | ||
827 | * | ||
828 | * Note: If DMA didn't stop continue | ||
829 | * since only a reset will fix it. | ||
830 | */ | ||
831 | ath5k_hw_dma_stop(ah); | ||
832 | |||
833 | /* | ||
826 | * Save some registers before a reset | 834 | * Save some registers before a reset |
827 | */ | 835 | */ |
828 | /*DCU/Antenna selection not available on 5210*/ | 836 | /*DCU/Antenna selection not available on 5210*/ |
@@ -1015,11 +1023,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
1015 | */ | 1023 | */ |
1016 | ath5k_hw_pcu_init(ah, op_mode, mode); | 1024 | ath5k_hw_pcu_init(ah, op_mode, mode); |
1017 | 1025 | ||
1018 | /* Clear any pending interrupts | ||
1019 | * PISR/SISR Not available on 5210 */ | ||
1020 | if (ah->ah_version != AR5K_AR5210) | ||
1021 | ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); | ||
1022 | |||
1023 | /* | 1026 | /* |
1024 | * Initialize PHY | 1027 | * Initialize PHY |
1025 | */ | 1028 | */ |