aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c108
1 files changed, 95 insertions, 13 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 1e481f3fcabf..b798fbabc3b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -29,6 +29,7 @@
29 29
30#include <linux/etherdevice.h> 30#include <linux/etherdevice.h>
31#include <linux/sched.h> 31#include <linux/sched.h>
32#include <linux/slab.h>
32#include <net/mac80211.h> 33#include <net/mac80211.h>
33#include "iwl-eeprom.h" 34#include "iwl-eeprom.h"
34#include "iwl-dev.h" 35#include "iwl-dev.h"
@@ -230,10 +231,34 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
230 struct iwl_queue *q = &txq->q; 231 struct iwl_queue *q = &txq->q;
231 struct device *dev = &priv->pci_dev->dev; 232 struct device *dev = &priv->pci_dev->dev;
232 int i; 233 int i;
234 bool huge = false;
233 235
234 if (q->n_bd == 0) 236 if (q->n_bd == 0)
235 return; 237 return;
236 238
239 for (; q->read_ptr != q->write_ptr;
240 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
241 /* we have no way to tell if it is a huge cmd ATM */
242 i = get_cmd_index(q, q->read_ptr, 0);
243
244 if (txq->meta[i].flags & CMD_SIZE_HUGE) {
245 huge = true;
246 continue;
247 }
248
249 pci_unmap_single(priv->pci_dev,
250 pci_unmap_addr(&txq->meta[i], mapping),
251 pci_unmap_len(&txq->meta[i], len),
252 PCI_DMA_BIDIRECTIONAL);
253 }
254 if (huge) {
255 i = q->n_window;
256 pci_unmap_single(priv->pci_dev,
257 pci_unmap_addr(&txq->meta[i], mapping),
258 pci_unmap_len(&txq->meta[i], len),
259 PCI_DMA_BIDIRECTIONAL);
260 }
261
237 /* De-alloc array of command/tx buffers */ 262 /* De-alloc array of command/tx buffers */
238 for (i = 0; i <= TFD_CMD_SLOTS; i++) 263 for (i = 0; i <= TFD_CMD_SLOTS; i++)
239 kfree(txq->cmd[i]); 264 kfree(txq->cmd[i]);
@@ -448,6 +473,26 @@ out_free_arrays:
448} 473}
449EXPORT_SYMBOL(iwl_tx_queue_init); 474EXPORT_SYMBOL(iwl_tx_queue_init);
450 475
476void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
477 int slots_num, u32 txq_id)
478{
479 int actual_slots = slots_num;
480
481 if (txq_id == IWL_CMD_QUEUE_NUM)
482 actual_slots++;
483
484 memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
485
486 txq->need_update = 0;
487
488 /* Initialize queue's high/low-water marks, and head/tail indexes */
489 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
490
491 /* Tell device where to find queue */
492 priv->cfg->ops->lib->txq_init(priv, txq);
493}
494EXPORT_SYMBOL(iwl_tx_queue_reset);
495
451/** 496/**
452 * iwl_hw_txq_ctx_free - Free TXQ Context 497 * iwl_hw_txq_ctx_free - Free TXQ Context
453 * 498 *
@@ -459,8 +504,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
459 504
460 /* Tx queues */ 505 /* Tx queues */
461 if (priv->txq) { 506 if (priv->txq) {
462 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; 507 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
463 txq_id++)
464 if (txq_id == IWL_CMD_QUEUE_NUM) 508 if (txq_id == IWL_CMD_QUEUE_NUM)
465 iwl_cmd_queue_free(priv); 509 iwl_cmd_queue_free(priv);
466 else 510 else
@@ -476,15 +520,15 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
476EXPORT_SYMBOL(iwl_hw_txq_ctx_free); 520EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
477 521
478/** 522/**
479 * iwl_txq_ctx_reset - Reset TX queue context 523 * iwl_txq_ctx_alloc - allocate TX queue context
480 * Destroys all DMA structures and initialize them again 524 * Allocate all Tx DMA structures and initialize them
481 * 525 *
482 * @param priv 526 * @param priv
483 * @return error code 527 * @return error code
484 */ 528 */
485int iwl_txq_ctx_reset(struct iwl_priv *priv) 529int iwl_txq_ctx_alloc(struct iwl_priv *priv)
486{ 530{
487 int ret = 0; 531 int ret;
488 int txq_id, slots_num; 532 int txq_id, slots_num;
489 unsigned long flags; 533 unsigned long flags;
490 534
@@ -542,8 +586,31 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
542 return ret; 586 return ret;
543} 587}
544 588
589void iwl_txq_ctx_reset(struct iwl_priv *priv)
590{
591 int txq_id, slots_num;
592 unsigned long flags;
593
594 spin_lock_irqsave(&priv->lock, flags);
595
596 /* Turn off all Tx DMA fifos */
597 priv->cfg->ops->lib->txq_set_sched(priv, 0);
598
599 /* Tell NIC where to find the "keep warm" buffer */
600 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
601
602 spin_unlock_irqrestore(&priv->lock, flags);
603
604 /* Alloc and init all Tx queues, including the command queue (#4) */
605 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
606 slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
607 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
608 iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
609 }
610}
611
545/** 612/**
546 * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory 613 * iwl_txq_ctx_stop - Stop all Tx DMA channels
547 */ 614 */
548void iwl_txq_ctx_stop(struct iwl_priv *priv) 615void iwl_txq_ctx_stop(struct iwl_priv *priv)
549{ 616{
@@ -563,9 +630,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
563 1000); 630 1000);
564 } 631 }
565 spin_unlock_irqrestore(&priv->lock, flags); 632 spin_unlock_irqrestore(&priv->lock, flags);
566
567 /* Deallocate memory for all Tx queues */
568 iwl_hw_txq_ctx_free(priv);
569} 633}
570EXPORT_SYMBOL(iwl_txq_ctx_stop); 634EXPORT_SYMBOL(iwl_txq_ctx_stop);
571 635
@@ -1075,6 +1139,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
1075 1139
1076 spin_lock_irqsave(&priv->hcmd_lock, flags); 1140 spin_lock_irqsave(&priv->hcmd_lock, flags);
1077 1141
1142 /* If this is a huge cmd, mark the huge flag also on the meta.flags
1143 * of the _original_ cmd. This is used for DMA mapping clean up.
1144 */
1145 if (cmd->flags & CMD_SIZE_HUGE) {
1146 idx = get_cmd_index(q, q->write_ptr, 0);
1147 txq->meta[idx].flags = CMD_SIZE_HUGE;
1148 }
1149
1078 idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); 1150 idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
1079 out_cmd = txq->cmd[idx]; 1151 out_cmd = txq->cmd[idx];
1080 out_meta = &txq->meta[idx]; 1152 out_meta = &txq->meta[idx];
@@ -1252,6 +1324,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1252 bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); 1324 bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
1253 struct iwl_device_cmd *cmd; 1325 struct iwl_device_cmd *cmd;
1254 struct iwl_cmd_meta *meta; 1326 struct iwl_cmd_meta *meta;
1327 struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
1255 1328
1256 /* If a Tx command is being handled and it isn't in the actual 1329 /* If a Tx command is being handled and it isn't in the actual
1257 * command queue then there a command routing bug has been introduced 1330 * command queue then there a command routing bug has been introduced
@@ -1265,9 +1338,17 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1265 return; 1338 return;
1266 } 1339 }
1267 1340
1268 cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); 1341 /* If this is a huge cmd, clear the huge flag on the meta.flags
1269 cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; 1342 * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap
1270 meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; 1343 * the DMA buffer for the scan (huge) command.
1344 */
1345 if (huge) {
1346 cmd_index = get_cmd_index(&txq->q, index, 0);
1347 txq->meta[cmd_index].flags = 0;
1348 }
1349 cmd_index = get_cmd_index(&txq->q, index, huge);
1350 cmd = txq->cmd[cmd_index];
1351 meta = &txq->meta[cmd_index];
1271 1352
1272 pci_unmap_single(priv->pci_dev, 1353 pci_unmap_single(priv->pci_dev,
1273 pci_unmap_addr(meta, mapping), 1354 pci_unmap_addr(meta, mapping),
@@ -1289,6 +1370,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
1289 get_cmd_string(cmd->hdr.cmd)); 1370 get_cmd_string(cmd->hdr.cmd));
1290 wake_up_interruptible(&priv->wait_command_queue); 1371 wake_up_interruptible(&priv->wait_command_queue);
1291 } 1372 }
1373 meta->flags = 0;
1292} 1374}
1293EXPORT_SYMBOL(iwl_tx_cmd_complete); 1375EXPORT_SYMBOL(iwl_tx_cmd_complete);
1294 1376