diff options
author | Zhu Yi <yi.zhu@intel.com> | 2010-03-22 05:28:41 -0400 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-04-02 14:12:20 -0400 |
commit | dd48744964296b5713032ea1d66eb9e3d990e287 (patch) | |
tree | 6ddda6cee4b7ba9848b568456083993f42b25c21 /drivers | |
parent | 7371400431389e1df6a2a05ab9882055b8a6ff2c (diff) |
iwlwifi: fix DMA allocation warnings
Below warning is triggered sometimes at module removal time when
CONFIG_DMA_API_DEBUG is enabled. This should be caused by we didn't
unmap pending commands (enqueued, but no complete notification
received) for the Tx command queue.
[ 1583.107469] ------------[ cut here ]------------
[ 1583.107539] WARNING: at lib/dma-debug.c:688
dma_debug_device_change+0x13c/0x180()
[ 1583.107617] Hardware name: ...
[ 1583.107664] pci 0000:04:00.0: DMA-API: device driver has pending DMA
allocations while released from device [count=1]
[ 1583.107713] Modules linked in: ...
[ 1583.111661] Pid: 16970, comm: modprobe Tainted: G W
2.6.34-rc1-wl #33
[ 1583.111727] Call Trace:
[ 1583.111779] [<c02a281c>] ? dma_debug_device_change+0x13c/0x180
[ 1583.111833] [<c02a281c>] ? dma_debug_device_change+0x13c/0x180
[ 1583.111908] [<c0138e11>] warn_slowpath_common+0x71/0xd0
[ 1583.111963] [<c02a281c>] ? dma_debug_device_change+0x13c/0x180
[ 1583.112016] [<c0138ebb>] warn_slowpath_fmt+0x2b/0x30
[ 1583.112086] [<c02a281c>] dma_debug_device_change+0x13c/0x180
[ 1583.112142] [<c03e6c33>] notifier_call_chain+0x53/0x90
[ 1583.112198] [<c03e1ebe>] ? down_read+0x6e/0x90
[ 1583.112271] [<c015b229>] __blocking_notifier_call_chain+0x49/0x70
[ 1583.112326] [<c015b26f>] blocking_notifier_call_chain+0x1f/0x30
[ 1583.112380] [<c031931c>] __device_release_driver+0x8c/0xa0
[ 1583.112451] [<c03193bf>] driver_detach+0x8f/0xa0
[ 1583.112538] [<c0318382>] bus_remove_driver+0x82/0x100
[ 1583.112595] [<c0319ad9>] driver_unregister+0x49/0x80
[ 1583.112671] [<c024feb2>] ? sysfs_remove_file+0x12/0x20
[ 1583.112727] [<c02aa292>] pci_unregister_driver+0x32/0x80
[ 1583.112791] [<fc13a3c1>] iwl_exit+0x12/0x19 [iwlagn]
[ 1583.112848] [<c017940a>] sys_delete_module+0x15a/0x210
[ 1583.112870] [<c015a5db>] ? up_read+0x1b/0x30
[ 1583.112893] [<c029600c>] ? trace_hardirqs_off_thunk+0xc/0x10
[ 1583.112924] [<c0295ffc>] ? trace_hardirqs_on_thunk+0xc/0x10
[ 1583.112947] [<c03e6a1f>] ? do_page_fault+0x1ff/0x3c0
[ 1583.112978] [<c03e36f6>] ? restore_all_notrace+0x0/0x18
[ 1583.113002] [<c016aa70>] ? trace_hardirqs_on_caller+0x20/0x190
[ 1583.113025] [<c0102d58>] sysenter_do_call+0x12/0x38
[ 1583.113054] ---[ end trace fc23e059cc4c2ced ]---
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers')
-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 | ||