diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-04-10 04:46:54 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-12 23:06:08 +0400 |
commit | 7c5ba4a830cbb730770129b0004e2a06e47dbac5 (patch) | |
tree | 3c86c616dbe30b31cd07d9d8720092932f84d05b /drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | |
parent | 52bcbff762a4cfedf97c46a58ec9890464212420 (diff) | |
download | linux-7c5ba4a830cbb730770129b0004e2a06e47dbac5.tar.xz |
iwlwifi: move queue watchdog into transport
This removes one of the two sources of device
restarts in the upper layer -- those are a bit
inconvenient because normal restarts originate
in the transport. By moving the watchdog down
it can be treated the same.
Also rewrite the watchdog logic. Timers are
much more efficient when they never fire, so
instead firing a timer every 500ms set up a
timer for each TX queue and fire it only when
the queue is really stuck. This avoids the CPU
waking up when everything is working well.
While at it, remove the wd_disable config item
and replace it by simply setting wd_timeout to
IWL_WATCHHDOG_DISABLED (0).
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index d35d0b81fd28..c34eac062762 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -668,6 +668,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) trace_bufs[2], trace_lens[2]); #endif + /* start timer if queue currently empty */ + if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) + mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_txq_update_write_ptr(trans, txq); @@ -677,6 +681,22 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) return idx; } +static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie, + struct iwl_tx_queue *txq) +{ + if (!trans_pcie->wd_timeout) + return; + + /* + * if empty delete timer, otherwise move timer forward + * since we're making progress on this queue + */ + if (txq->q.read_ptr == txq->q.write_ptr) + del_timer(&txq->stuck_timer); + else + mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); +} + /** * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd * @@ -711,6 +731,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, } } + + iwl_queue_progress(trans_pcie, txq); } /** @@ -754,8 +776,6 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb, cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; - txq->time_stamp = jiffies; - iwlagn_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); @@ -949,5 +969,8 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE); freed++; } + + iwl_queue_progress(trans_pcie, txq); + return freed; } |