aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-tx.c
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-04-08 13:34:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-04-08 13:34:54 -0400
commit0f2df9eac70423838a1f8d410fd3899ddd88317b (patch)
tree0617f723320d83eca5cef9c964c001014e74213f /drivers/net/wireless/iwlwifi/iwl-tx.c
parent8c11e4ab09ffb975a89802dde0e9aa52a53b8aa5 (diff)
parent1144601118507f8b3b676a9a392584d216d3f2cc (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6 into merge
Conflicts: Documentation/feature-removal-schedule.txt drivers/net/wireless/ath/ath5k/phy.c drivers/net/wireless/iwlwifi/iwl-4965.c drivers/net/wireless/iwlwifi/iwl-agn.c drivers/net/wireless/iwlwifi/iwl-core.c drivers/net/wireless/iwlwifi/iwl-core.h drivers/net/wireless/iwlwifi/iwl-tx.c
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 65090d386a53..a631afef5e33 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -83,7 +83,7 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
83 if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed) 83 if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
84 priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; 84 priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
85 else { 85 else {
86 IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n", 86 IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
87 priv->stations[sta_id].tid[tid].tfds_in_queue, 87 priv->stations[sta_id].tid[tid].tfds_in_queue,
88 freed); 88 freed);
89 priv->stations[sta_id].tid[tid].tfds_in_queue = 0; 89 priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
@@ -152,10 +152,34 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
152 struct iwl_queue *q = &txq->q; 152 struct iwl_queue *q = &txq->q;
153 struct device *dev = &priv->pci_dev->dev; 153 struct device *dev = &priv->pci_dev->dev;
154 int i; 154 int i;
155 bool huge = false;
155 156
156 if (q->n_bd == 0) 157 if (q->n_bd == 0)
157 return; 158 return;
158 159
160 for (; q->read_ptr != q->write_ptr;
161 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
162 /* we have no way to tell if it is a huge cmd ATM */
163 i = get_cmd_index(q, q->read_ptr, 0);
164
165 if (txq->meta[i].flags & CMD_SIZE_HUGE) {
166 huge = true;
167 continue;
168 }
169
170 pci_unmap_single(priv->pci_dev,
171 pci_unmap_addr(&txq->meta[i], mapping),
172 pci_unmap_len(&txq->meta[i], len),
173 PCI_DMA_BIDIRECTIONAL);
174 }
175 if (huge) {
176 i = q->n_window;
177 pci_unmap_single(priv->pci_dev,
178 pci_unmap_addr(&txq->meta[i], mapping),
179 pci_unmap_len(&txq->meta[i], len),
180 PCI_DMA_BIDIRECTIONAL);
181 }
182
159 /* De-alloc array of command/tx buffers */ 183 /* De-alloc array of command/tx buffers */
160 for (i = 0; i <= TFD_CMD_SLOTS; i++) 184 for (i = 0; i <= TFD_CMD_SLOTS; i++)
161 kfree(txq->cmd[i]); 185 kfree(txq->cmd[i]);
@@ -424,6 +448,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
424 448
425 spin_lock_irqsave(&priv->hcmd_lock, flags); 449 spin_lock_irqsave(&priv->hcmd_lock, flags);
426 450
451 /* If this is a huge cmd, mark the huge flag also on the meta.flags
452 * of the _original_ cmd. This is used for DMA mapping clean up.
453 */
454 if (cmd->flags & CMD_SIZE_HUGE) {
455 idx = get_cmd_index(q, q->write_ptr, 0);
456 txq->meta[idx].flags = CMD_SIZE_HUGE;
457 }
458
427 idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); 459 idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
428 out_cmd = txq->cmd[idx]; 460 out_cmd = txq->cmd[idx];
429 out_meta = &txq->meta[idx]; 461 out_meta = &txq->meta[idx];
@@ -546,6 +578,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
546 bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); 578 bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
547 struct iwl_device_cmd *cmd; 579 struct iwl_device_cmd *cmd;
548 struct iwl_cmd_meta *meta; 580 struct iwl_cmd_meta *meta;
581 struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
549 582
550 /* If a Tx command is being handled and it isn't in the actual 583 /* If a Tx command is being handled and it isn't in the actual
551 * command queue then there a command routing bug has been introduced 584 * command queue then there a command routing bug has been introduced
@@ -559,9 +592,17 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
559 return; 592 return;
560 } 593 }
561 594
562 cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); 595 /* If this is a huge cmd, clear the huge flag on the meta.flags
563 cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; 596 * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap
564 meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; 597 * the DMA buffer for the scan (huge) command.
598 */
599 if (huge) {
600 cmd_index = get_cmd_index(&txq->q, index, 0);
601 txq->meta[cmd_index].flags = 0;
602 }
603 cmd_index = get_cmd_index(&txq->q, index, huge);
604 cmd = txq->cmd[cmd_index];
605 meta = &txq->meta[cmd_index];
565 606
566 pci_unmap_single(priv->pci_dev, 607 pci_unmap_single(priv->pci_dev,
567 pci_unmap_addr(meta, mapping), 608 pci_unmap_addr(meta, mapping),
@@ -583,6 +624,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
583 get_cmd_string(cmd->hdr.cmd)); 624 get_cmd_string(cmd->hdr.cmd));
584 wake_up_interruptible(&priv->wait_command_queue); 625 wake_up_interruptible(&priv->wait_command_queue);
585 } 626 }
627 meta->flags = 0;
586} 628}
587EXPORT_SYMBOL(iwl_tx_cmd_complete); 629EXPORT_SYMBOL(iwl_tx_cmd_complete);
588 630