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 | ||
