Commit d41174fa authored by Nick Kossifidis's avatar Nick Kossifidis Committed by John W. Linville

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: default avatarNick Kossifidis <mickflemm@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9320b5c4
...@@ -1180,8 +1180,9 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); ...@@ -1180,8 +1180,9 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask); enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
void ath5k_hw_update_mib_counters(struct ath5k_hw *ah); void ath5k_hw_update_mib_counters(struct ath5k_hw *ah);
/* Init function */ /* Init/Stop functions */
void ath5k_hw_dma_init(struct ath5k_hw *ah); void ath5k_hw_dma_init(struct ath5k_hw *ah);
int ath5k_hw_dma_stop(struct ath5k_hw *ah);
/* EEPROM access functions */ /* EEPROM access functions */
int ath5k_eeprom_init(struct ath5k_hw *ah); int ath5k_eeprom_init(struct ath5k_hw *ah);
......
...@@ -126,7 +126,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue) ...@@ -126,7 +126,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Return if queue is declared inactive */ /* Return if queue is declared inactive */
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
return -EIO; return -EINVAL;
if (ah->ah_version == AR5K_AR5210) { if (ah->ah_version == AR5K_AR5210) {
tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); 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,7 +174,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
* *
* Stop DMA transmit on a specific hw queue and drain queue so we don't * Stop DMA transmit on a specific hw queue and drain queue so we don't
* have any pending frames. Returns -EBUSY if we still have pending frames, * have any pending frames. Returns -EBUSY if we still have pending frames,
* -EINVAL if queue number is out of range. * -EINVAL if queue number is out of range or inactive.
* *
*/ */
int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) 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,7 +186,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Return if queue is declared inactive */ /* Return if queue is declared inactive */
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
return -EIO; return -EINVAL;
if (ah->ah_version == AR5K_AR5210) { if (ah->ah_version == AR5K_AR5210) {
tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
...@@ -733,3 +733,49 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah) ...@@ -733,3 +733,49 @@ void ath5k_hw_dma_init(struct ath5k_hw *ah)
ath5k_hw_set_imr(ah, ah->ah_imr); ath5k_hw_set_imr(ah, ah->ah_imr);
} }
/**
* ath5k_hw_dma_stop - stop DMA unit
*
* @ah: The &struct ath5k_hw
*
* Stop tx/rx DMA and interrupts. Returns
* -EBUSY if tx or rx dma failed to stop.
*
* XXX: Sometimes DMA unit hangs and we have
* stuck frames on tx queues, only a reset
* can fix that.
*/
int ath5k_hw_dma_stop(struct ath5k_hw *ah)
{
int i, qmax, err;
err = 0;
/* Disable interrupts */
ath5k_hw_set_imr(ah, 0);
/* Stop rx dma */
err = ath5k_hw_stop_rx_dma(ah);
if (err)
return err;
/* Clear any pending interrupts
* and disable tx dma */
if (ah->ah_version != AR5K_AR5210) {
ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
qmax = AR5K_NUM_TX_QUEUES;
} else {
/* PISR/SISR Not available on 5210 */
ath5k_hw_reg_read(ah, AR5K_ISR);
qmax = AR5K_NUM_TX_QUEUES_NOQCU;
}
for (i = 0; i < qmax; i++) {
err = ath5k_hw_stop_tx_dma(ah, i);
/* -EINVAL -> queue inactive */
if (err != -EINVAL)
return err;
}
return err;
}
...@@ -822,6 +822,14 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ...@@ -822,6 +822,14 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
freq = 0; freq = 0;
mode = 0; mode = 0;
/*
* Stop DMA
*
* Note: If DMA didn't stop continue
* since only a reset will fix it.
*/
ath5k_hw_dma_stop(ah);
/* /*
* Save some registers before a reset * Save some registers before a reset
*/ */
...@@ -1015,11 +1023,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ...@@ -1015,11 +1023,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
*/ */
ath5k_hw_pcu_init(ah, op_mode, mode); ath5k_hw_pcu_init(ah, op_mode, mode);
/* Clear any pending interrupts
* PISR/SISR Not available on 5210 */
if (ah->ah_version != AR5K_AR5210)
ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
/* /*
* Initialize PHY * Initialize PHY
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment