diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/dma.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/dma.c | 180 |
1 files changed, 168 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 923c9ca5c4f0..82541fec9f0e 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "debug.h" | 37 | #include "debug.h" |
38 | #include "base.h" | 38 | #include "base.h" |
39 | 39 | ||
40 | |||
40 | /*********\ | 41 | /*********\ |
41 | * Receive * | 42 | * Receive * |
42 | \*********/ | 43 | \*********/ |
@@ -57,7 +58,7 @@ void ath5k_hw_start_rx_dma(struct ath5k_hw *ah) | |||
57 | * | 58 | * |
58 | * @ah: The &struct ath5k_hw | 59 | * @ah: The &struct ath5k_hw |
59 | */ | 60 | */ |
60 | int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) | 61 | static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) |
61 | { | 62 | { |
62 | unsigned int i; | 63 | unsigned int i; |
63 | 64 | ||
@@ -69,7 +70,11 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) | |||
69 | for (i = 1000; i > 0 && | 70 | for (i = 1000; i > 0 && |
70 | (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; | 71 | (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; |
71 | i--) | 72 | i--) |
72 | udelay(10); | 73 | udelay(100); |
74 | |||
75 | if (i) | ||
76 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA, | ||
77 | "failed to stop RX DMA !\n"); | ||
73 | 78 | ||
74 | return i ? 0 : -EBUSY; | 79 | return i ? 0 : -EBUSY; |
75 | } | 80 | } |
@@ -90,11 +95,18 @@ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah) | |||
90 | * @ah: The &struct ath5k_hw | 95 | * @ah: The &struct ath5k_hw |
91 | * @phys_addr: RX descriptor address | 96 | * @phys_addr: RX descriptor address |
92 | * | 97 | * |
93 | * XXX: Should we check if rx is enabled before setting rxdp ? | 98 | * Returns -EIO if rx is active |
94 | */ | 99 | */ |
95 | void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) | 100 | int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr) |
96 | { | 101 | { |
102 | if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) { | ||
103 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA, | ||
104 | "tried to set RXDP while rx was active !\n"); | ||
105 | return -EIO; | ||
106 | } | ||
107 | |||
97 | ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); | 108 | ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); |
109 | return 0; | ||
98 | } | 110 | } |
99 | 111 | ||
100 | 112 | ||
@@ -125,7 +137,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
125 | 137 | ||
126 | /* Return if queue is declared inactive */ | 138 | /* Return if queue is declared inactive */ |
127 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | 139 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) |
128 | return -EIO; | 140 | return -EINVAL; |
129 | 141 | ||
130 | if (ah->ah_version == AR5K_AR5210) { | 142 | if (ah->ah_version == AR5K_AR5210) { |
131 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); | 143 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); |
@@ -173,10 +185,10 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
173 | * | 185 | * |
174 | * Stop DMA transmit on a specific hw queue and drain queue so we don't | 186 | * Stop DMA transmit on a specific hw queue and drain queue so we don't |
175 | * have any pending frames. Returns -EBUSY if we still have pending frames, | 187 | * have any pending frames. Returns -EBUSY if we still have pending frames, |
176 | * -EINVAL if queue number is out of range. | 188 | * -EINVAL if queue number is out of range or inactive. |
177 | * | 189 | * |
178 | */ | 190 | */ |
179 | int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | 191 | static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) |
180 | { | 192 | { |
181 | unsigned int i = 40; | 193 | unsigned int i = 40; |
182 | u32 tx_queue, pending; | 194 | u32 tx_queue, pending; |
@@ -185,7 +197,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
185 | 197 | ||
186 | /* Return if queue is declared inactive */ | 198 | /* Return if queue is declared inactive */ |
187 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) | 199 | if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) |
188 | return -EIO; | 200 | return -EINVAL; |
189 | 201 | ||
190 | if (ah->ah_version == AR5K_AR5210) { | 202 | if (ah->ah_version == AR5K_AR5210) { |
191 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); | 203 | tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); |
@@ -211,12 +223,31 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
211 | ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); | 223 | ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); |
212 | ath5k_hw_reg_read(ah, AR5K_CR); | 224 | ath5k_hw_reg_read(ah, AR5K_CR); |
213 | } else { | 225 | } else { |
226 | |||
227 | /* | ||
228 | * Enable DCU early termination to quickly | ||
229 | * flush any pending frames from QCU | ||
230 | */ | ||
231 | AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | ||
232 | AR5K_QCU_MISC_DCU_EARLY); | ||
233 | |||
214 | /* | 234 | /* |
215 | * Schedule TX disable and wait until queue is empty | 235 | * Schedule TX disable and wait until queue is empty |
216 | */ | 236 | */ |
217 | AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); | 237 | AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); |
218 | 238 | ||
219 | /*Check for pending frames*/ | 239 | /* Wait for queue to stop */ |
240 | for (i = 1000; i > 0 && | ||
241 | (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue) != 0); | ||
242 | i--) | ||
243 | udelay(100); | ||
244 | |||
245 | if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) | ||
246 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA, | ||
247 | "queue %i didn't stop !\n", queue); | ||
248 | |||
249 | /* Check for pending frames */ | ||
250 | i = 1000; | ||
220 | do { | 251 | do { |
221 | pending = ath5k_hw_reg_read(ah, | 252 | pending = ath5k_hw_reg_read(ah, |
222 | AR5K_QUEUE_STATUS(queue)) & | 253 | AR5K_QUEUE_STATUS(queue)) & |
@@ -247,12 +278,12 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
247 | AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); | 278 | AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); |
248 | 279 | ||
249 | /* Wait a while and disable mechanism */ | 280 | /* Wait a while and disable mechanism */ |
250 | udelay(200); | 281 | udelay(400); |
251 | AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1, | 282 | AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1, |
252 | AR5K_QUIET_CTL1_QT_EN); | 283 | AR5K_QUIET_CTL1_QT_EN); |
253 | 284 | ||
254 | /* Re-check for pending frames */ | 285 | /* Re-check for pending frames */ |
255 | i = 40; | 286 | i = 100; |
256 | do { | 287 | do { |
257 | pending = ath5k_hw_reg_read(ah, | 288 | pending = ath5k_hw_reg_read(ah, |
258 | AR5K_QUEUE_STATUS(queue)) & | 289 | AR5K_QUEUE_STATUS(queue)) & |
@@ -262,12 +293,27 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
262 | 293 | ||
263 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, | 294 | AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211, |
264 | AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); | 295 | AR5K_DIAG_SW_CHANNEL_IDLE_HIGH); |
296 | |||
297 | if (pending) | ||
298 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA, | ||
299 | "quiet mechanism didn't work q:%i !\n", | ||
300 | queue); | ||
265 | } | 301 | } |
266 | 302 | ||
303 | /* | ||
304 | * Disable DCU early termination | ||
305 | */ | ||
306 | AR5K_REG_DISABLE_BITS(ah, AR5K_QUEUE_MISC(queue), | ||
307 | AR5K_QCU_MISC_DCU_EARLY); | ||
308 | |||
267 | /* Clear register */ | 309 | /* Clear register */ |
268 | ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); | 310 | ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); |
269 | if (pending) | 311 | if (pending) { |
312 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA, | ||
313 | "tx dma didn't stop (q:%i, frm:%i) !\n", | ||
314 | queue, pending); | ||
270 | return -EBUSY; | 315 | return -EBUSY; |
316 | } | ||
271 | } | 317 | } |
272 | 318 | ||
273 | /* TODO: Check for success on 5210 else return error */ | 319 | /* TODO: Check for success on 5210 else return error */ |
@@ -275,6 +321,26 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) | |||
275 | } | 321 | } |
276 | 322 | ||
277 | /** | 323 | /** |
324 | * ath5k_hw_stop_beacon_queue - Stop beacon queue | ||
325 | * | ||
326 | * @ah The &struct ath5k_hw | ||
327 | * @queue The queue number | ||
328 | * | ||
329 | * Returns -EIO if queue didn't stop | ||
330 | */ | ||
331 | int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue) | ||
332 | { | ||
333 | int ret; | ||
334 | ret = ath5k_hw_stop_tx_dma(ah, queue); | ||
335 | if (ret) { | ||
336 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA, | ||
337 | "beacon queue didn't stop !\n"); | ||
338 | return -EIO; | ||
339 | } | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | /** | ||
278 | * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue | 344 | * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue |
279 | * | 345 | * |
280 | * @ah: The &struct ath5k_hw | 346 | * @ah: The &struct ath5k_hw |
@@ -427,6 +493,7 @@ done: | |||
427 | return ret; | 493 | return ret; |
428 | } | 494 | } |
429 | 495 | ||
496 | |||
430 | /*******************\ | 497 | /*******************\ |
431 | * Interrupt masking * | 498 | * Interrupt masking * |
432 | \*******************/ | 499 | \*******************/ |
@@ -688,3 +755,92 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) | |||
688 | return old_mask; | 755 | return old_mask; |
689 | } | 756 | } |
690 | 757 | ||
758 | |||
759 | /********************\ | ||
760 | Init/Stop functions | ||
761 | \********************/ | ||
762 | |||
763 | /** | ||
764 | * ath5k_hw_dma_init - Initialize DMA unit | ||
765 | * | ||
766 | * @ah: The &struct ath5k_hw | ||
767 | * | ||
768 | * Set DMA size and pre-enable interrupts | ||
769 | * (driver handles tx/rx buffer setup and | ||
770 | * dma start/stop) | ||
771 | * | ||
772 | * XXX: Save/restore RXDP/TXDP registers ? | ||
773 | */ | ||
774 | void ath5k_hw_dma_init(struct ath5k_hw *ah) | ||
775 | { | ||
776 | /* | ||
777 | * Set Rx/Tx DMA Configuration | ||
778 | * | ||
779 | * Set standard DMA size (128). Note that | ||
780 | * a DMA size of 512 causes rx overruns and tx errors | ||
781 | * on pci-e cards (tested on 5424 but since rx overruns | ||
782 | * also occur on 5416/5418 with madwifi we set 128 | ||
783 | * for all PCI-E cards to be safe). | ||
784 | * | ||
785 | * XXX: need to check 5210 for this | ||
786 | * TODO: Check out tx triger level, it's always 64 on dumps but I | ||
787 | * guess we can tweak it and see how it goes ;-) | ||
788 | */ | ||
789 | if (ah->ah_version != AR5K_AR5210) { | ||
790 | AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, | ||
791 | AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); | ||
792 | AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, | ||
793 | AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B); | ||
794 | } | ||
795 | |||
796 | /* Pre-enable interrupts on 5211/5212*/ | ||
797 | if (ah->ah_version != AR5K_AR5210) | ||
798 | ath5k_hw_set_imr(ah, ah->ah_imr); | ||
799 | |||
800 | } | ||
801 | |||
802 | /** | ||
803 | * ath5k_hw_dma_stop - stop DMA unit | ||
804 | * | ||
805 | * @ah: The &struct ath5k_hw | ||
806 | * | ||
807 | * Stop tx/rx DMA and interrupts. Returns | ||
808 | * -EBUSY if tx or rx dma failed to stop. | ||
809 | * | ||
810 | * XXX: Sometimes DMA unit hangs and we have | ||
811 | * stuck frames on tx queues, only a reset | ||
812 | * can fix that. | ||
813 | */ | ||
814 | int ath5k_hw_dma_stop(struct ath5k_hw *ah) | ||
815 | { | ||
816 | int i, qmax, err; | ||
817 | err = 0; | ||
818 | |||
819 | /* Disable interrupts */ | ||
820 | ath5k_hw_set_imr(ah, 0); | ||
821 | |||
822 | /* Stop rx dma */ | ||
823 | err = ath5k_hw_stop_rx_dma(ah); | ||
824 | if (err) | ||
825 | return err; | ||
826 | |||
827 | /* Clear any pending interrupts | ||
828 | * and disable tx dma */ | ||
829 | if (ah->ah_version != AR5K_AR5210) { | ||
830 | ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); | ||
831 | qmax = AR5K_NUM_TX_QUEUES; | ||
832 | } else { | ||
833 | /* PISR/SISR Not available on 5210 */ | ||
834 | ath5k_hw_reg_read(ah, AR5K_ISR); | ||
835 | qmax = AR5K_NUM_TX_QUEUES_NOQCU; | ||
836 | } | ||
837 | |||
838 | for (i = 0; i < qmax; i++) { | ||
839 | err = ath5k_hw_stop_tx_dma(ah, i); | ||
840 | /* -EINVAL -> queue inactive */ | ||
841 | if (err != -EINVAL) | ||
842 | return err; | ||
843 | } | ||
844 | |||
845 | return err; | ||
846 | } | ||