diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 8c12311dbb0a..6aa309032f4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -193,10 +193,34 @@ void iwl_cmd_queue_free(struct iwl_priv *priv) | |||
193 | struct iwl_queue *q = &txq->q; | 193 | struct iwl_queue *q = &txq->q; |
194 | struct device *dev = &priv->pci_dev->dev; | 194 | struct device *dev = &priv->pci_dev->dev; |
195 | int i; | 195 | int i; |
196 | bool huge = false; | ||
196 | 197 | ||
197 | if (q->n_bd == 0) | 198 | if (q->n_bd == 0) |
198 | return; | 199 | return; |
199 | 200 | ||
201 | for (; q->read_ptr != q->write_ptr; | ||
202 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
203 | /* we have no way to tell if it is a huge cmd ATM */ | ||
204 | i = get_cmd_index(q, q->read_ptr, 0); | ||
205 | |||
206 | if (txq->meta[i].flags & CMD_SIZE_HUGE) { | ||
207 | huge = true; | ||
208 | continue; | ||
209 | } | ||
210 | |||
211 | pci_unmap_single(priv->pci_dev, | ||
212 | pci_unmap_addr(&txq->meta[i], mapping), | ||
213 | pci_unmap_len(&txq->meta[i], len), | ||
214 | PCI_DMA_BIDIRECTIONAL); | ||
215 | } | ||
216 | if (huge) { | ||
217 | i = q->n_window; | ||
218 | pci_unmap_single(priv->pci_dev, | ||
219 | pci_unmap_addr(&txq->meta[i], mapping), | ||
220 | pci_unmap_len(&txq->meta[i], len), | ||
221 | PCI_DMA_BIDIRECTIONAL); | ||
222 | } | ||
223 | |||
200 | /* De-alloc array of command/tx buffers */ | 224 | /* De-alloc array of command/tx buffers */ |
201 | for (i = 0; i <= TFD_CMD_SLOTS; i++) | 225 | for (i = 0; i <= TFD_CMD_SLOTS; i++) |
202 | kfree(txq->cmd[i]); | 226 | kfree(txq->cmd[i]); |
@@ -1049,6 +1073,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
1049 | 1073 | ||
1050 | spin_lock_irqsave(&priv->hcmd_lock, flags); | 1074 | spin_lock_irqsave(&priv->hcmd_lock, flags); |
1051 | 1075 | ||
1076 | /* If this is a huge cmd, mark the huge flag also on the meta.flags | ||
1077 | * of the _original_ cmd. This is used for DMA mapping clean up. | ||
1078 | */ | ||
1079 | if (cmd->flags & CMD_SIZE_HUGE) { | ||
1080 | idx = get_cmd_index(q, q->write_ptr, 0); | ||
1081 | txq->meta[idx].flags = CMD_SIZE_HUGE; | ||
1082 | } | ||
1083 | |||
1052 | idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); | 1084 | idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); |
1053 | out_cmd = txq->cmd[idx]; | 1085 | out_cmd = txq->cmd[idx]; |
1054 | out_meta = &txq->meta[idx]; | 1086 | out_meta = &txq->meta[idx]; |
@@ -1226,6 +1258,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
1226 | bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); | 1258 | bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME); |
1227 | struct iwl_device_cmd *cmd; | 1259 | struct iwl_device_cmd *cmd; |
1228 | struct iwl_cmd_meta *meta; | 1260 | struct iwl_cmd_meta *meta; |
1261 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; | ||
1229 | 1262 | ||
1230 | /* If a Tx command is being handled and it isn't in the actual | 1263 | /* If a Tx command is being handled and it isn't in the actual |
1231 | * command queue then there a command routing bug has been introduced | 1264 | * command queue then there a command routing bug has been introduced |
@@ -1239,9 +1272,17 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
1239 | return; | 1272 | return; |
1240 | } | 1273 | } |
1241 | 1274 | ||
1242 | cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); | 1275 | /* If this is a huge cmd, clear the huge flag on the meta.flags |
1243 | cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; | 1276 | * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap |
1244 | meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index]; | 1277 | * the DMA buffer for the scan (huge) command. |
1278 | */ | ||
1279 | if (huge) { | ||
1280 | cmd_index = get_cmd_index(&txq->q, index, 0); | ||
1281 | txq->meta[cmd_index].flags = 0; | ||
1282 | } | ||
1283 | cmd_index = get_cmd_index(&txq->q, index, huge); | ||
1284 | cmd = txq->cmd[cmd_index]; | ||
1285 | meta = &txq->meta[cmd_index]; | ||
1245 | 1286 | ||
1246 | pci_unmap_single(priv->pci_dev, | 1287 | pci_unmap_single(priv->pci_dev, |
1247 | pci_unmap_addr(meta, mapping), | 1288 | pci_unmap_addr(meta, mapping), |
@@ -1263,6 +1304,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | |||
1263 | get_cmd_string(cmd->hdr.cmd)); | 1304 | get_cmd_string(cmd->hdr.cmd)); |
1264 | wake_up_interruptible(&priv->wait_command_queue); | 1305 | wake_up_interruptible(&priv->wait_command_queue); |
1265 | } | 1306 | } |
1307 | meta->flags = 0; | ||
1266 | } | 1308 | } |
1267 | EXPORT_SYMBOL(iwl_tx_cmd_complete); | 1309 | EXPORT_SYMBOL(iwl_tx_cmd_complete); |
1268 | 1310 | ||