diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2011-02-28 08:33:14 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-02-28 14:06:56 -0500 |
commit | 8a032c132b7ca011813df7c441b4a6fc89e5baee (patch) | |
tree | 5d716fbbd4c232c469da47e109752c8ee52bb57e /drivers | |
parent | 387f3381f732d8fa1b62213ae3276f2ae712dbe2 (diff) |
iwlegacy: fix dma mappings and skbs leak
Fix possible dma mappings and skbs introduced by commit
470058e0ad82fcfaaffd57307d8bf8c094e8e9d7 "iwlwifi: avoid Tx queue
memory allocation in interface down".
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlegacy/iwl-4965-tx.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlegacy/iwl-core.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlegacy/iwl-tx.c | 75 |
3 files changed, 62 insertions, 27 deletions
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index 829db91896b0..5c40502f869a 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c | |||
@@ -698,7 +698,7 @@ void iwl4965_txq_ctx_reset(struct iwl_priv *priv) | |||
698 | */ | 698 | */ |
699 | void iwl4965_txq_ctx_stop(struct iwl_priv *priv) | 699 | void iwl4965_txq_ctx_stop(struct iwl_priv *priv) |
700 | { | 700 | { |
701 | int ch; | 701 | int ch, txq_id; |
702 | unsigned long flags; | 702 | unsigned long flags; |
703 | 703 | ||
704 | /* Turn off all Tx DMA fifos */ | 704 | /* Turn off all Tx DMA fifos */ |
@@ -719,6 +719,16 @@ void iwl4965_txq_ctx_stop(struct iwl_priv *priv) | |||
719 | FH_TSSR_TX_STATUS_REG)); | 719 | FH_TSSR_TX_STATUS_REG)); |
720 | } | 720 | } |
721 | spin_unlock_irqrestore(&priv->lock, flags); | 721 | spin_unlock_irqrestore(&priv->lock, flags); |
722 | |||
723 | if (!priv->txq) | ||
724 | return; | ||
725 | |||
726 | /* Unmap DMA from host system and free skb's */ | ||
727 | for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) | ||
728 | if (txq_id == priv->cmd_queue) | ||
729 | iwl_legacy_cmd_queue_unmap(priv); | ||
730 | else | ||
731 | iwl_legacy_tx_queue_unmap(priv, txq_id); | ||
722 | } | 732 | } |
723 | 733 | ||
724 | /* | 734 | /* |
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index c6d12d7e96b6..f03b463e4378 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h | |||
@@ -388,6 +388,7 @@ void iwl_legacy_rx_reply_error(struct iwl_priv *priv, | |||
388 | /***************************************************** | 388 | /***************************************************** |
389 | * RX | 389 | * RX |
390 | ******************************************************/ | 390 | ******************************************************/ |
391 | void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv); | ||
391 | void iwl_legacy_cmd_queue_free(struct iwl_priv *priv); | 392 | void iwl_legacy_cmd_queue_free(struct iwl_priv *priv); |
392 | int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv); | 393 | int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv); |
393 | void iwl_legacy_rx_queue_update_write_ptr(struct iwl_priv *priv, | 394 | void iwl_legacy_rx_queue_update_write_ptr(struct iwl_priv *priv, |
@@ -415,6 +416,7 @@ int iwl_legacy_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, | |||
415 | void iwl_legacy_tx_queue_reset(struct iwl_priv *priv, | 416 | void iwl_legacy_tx_queue_reset(struct iwl_priv *priv, |
416 | struct iwl_tx_queue *txq, | 417 | struct iwl_tx_queue *txq, |
417 | int slots_num, u32 txq_id); | 418 | int slots_num, u32 txq_id); |
419 | void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id); | ||
418 | void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id); | 420 | void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id); |
419 | void iwl_legacy_setup_watchdog(struct iwl_priv *priv); | 421 | void iwl_legacy_setup_watchdog(struct iwl_priv *priv); |
420 | /***************************************************** | 422 | /***************************************************** |
diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index 7db8340d1c07..a227773cb384 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c | |||
@@ -82,6 +82,24 @@ iwl_legacy_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
82 | EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr); | 82 | EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr); |
83 | 83 | ||
84 | /** | 84 | /** |
85 | * iwl_legacy_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's | ||
86 | */ | ||
87 | void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id) | ||
88 | { | ||
89 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | ||
90 | struct iwl_queue *q = &txq->q; | ||
91 | |||
92 | if (q->n_bd == 0) | ||
93 | return; | ||
94 | |||
95 | while (q->write_ptr != q->read_ptr) { | ||
96 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); | ||
97 | q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd); | ||
98 | } | ||
99 | } | ||
100 | EXPORT_SYMBOL(iwl_legacy_tx_queue_unmap); | ||
101 | |||
102 | /** | ||
85 | * iwl_legacy_tx_queue_free - Deallocate DMA queue. | 103 | * iwl_legacy_tx_queue_free - Deallocate DMA queue. |
86 | * @txq: Transmit queue to deallocate. | 104 | * @txq: Transmit queue to deallocate. |
87 | * | 105 | * |
@@ -92,17 +110,10 @@ EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr); | |||
92 | void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id) | 110 | void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id) |
93 | { | 111 | { |
94 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 112 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; |
95 | struct iwl_queue *q = &txq->q; | ||
96 | struct device *dev = &priv->pci_dev->dev; | 113 | struct device *dev = &priv->pci_dev->dev; |
97 | int i; | 114 | int i; |
98 | 115 | ||
99 | if (q->n_bd == 0) | 116 | iwl_legacy_tx_queue_unmap(priv, txq_id); |
100 | return; | ||
101 | |||
102 | /* first, empty all BD's */ | ||
103 | for (; q->write_ptr != q->read_ptr; | ||
104 | q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) | ||
105 | priv->cfg->ops->lib->txq_free_tfd(priv, txq); | ||
106 | 117 | ||
107 | /* De-alloc array of command/tx buffers */ | 118 | /* De-alloc array of command/tx buffers */ |
108 | for (i = 0; i < TFD_TX_CMD_SLOTS; i++) | 119 | for (i = 0; i < TFD_TX_CMD_SLOTS; i++) |
@@ -129,39 +140,33 @@ void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id) | |||
129 | EXPORT_SYMBOL(iwl_legacy_tx_queue_free); | 140 | EXPORT_SYMBOL(iwl_legacy_tx_queue_free); |
130 | 141 | ||
131 | /** | 142 | /** |
132 | * iwl_legacy_cmd_queue_free - Deallocate DMA queue. | 143 | * iwl_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue |
133 | * @txq: Transmit queue to deallocate. | ||
134 | * | ||
135 | * Empty queue by removing and destroying all BD's. | ||
136 | * Free all buffers. | ||
137 | * 0-fill, but do not free "txq" descriptor structure. | ||
138 | */ | 144 | */ |
139 | void iwl_legacy_cmd_queue_free(struct iwl_priv *priv) | 145 | void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv) |
140 | { | 146 | { |
141 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; | 147 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; |
142 | struct iwl_queue *q = &txq->q; | 148 | struct iwl_queue *q = &txq->q; |
143 | struct device *dev = &priv->pci_dev->dev; | ||
144 | int i; | ||
145 | bool huge = false; | 149 | bool huge = false; |
150 | int i; | ||
146 | 151 | ||
147 | if (q->n_bd == 0) | 152 | if (q->n_bd == 0) |
148 | return; | 153 | return; |
149 | 154 | ||
150 | for (; q->read_ptr != q->write_ptr; | 155 | while (q->read_ptr != q->write_ptr) { |
151 | q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) { | ||
152 | /* we have no way to tell if it is a huge cmd ATM */ | 156 | /* we have no way to tell if it is a huge cmd ATM */ |
153 | i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); | 157 | i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); |
154 | 158 | ||
155 | if (txq->meta[i].flags & CMD_SIZE_HUGE) { | 159 | if (txq->meta[i].flags & CMD_SIZE_HUGE) |
156 | huge = true; | 160 | huge = true; |
157 | continue; | 161 | else |
158 | } | 162 | pci_unmap_single(priv->pci_dev, |
163 | dma_unmap_addr(&txq->meta[i], mapping), | ||
164 | dma_unmap_len(&txq->meta[i], len), | ||
165 | PCI_DMA_BIDIRECTIONAL); | ||
159 | 166 | ||
160 | pci_unmap_single(priv->pci_dev, | 167 | q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd); |
161 | dma_unmap_addr(&txq->meta[i], mapping), | ||
162 | dma_unmap_len(&txq->meta[i], len), | ||
163 | PCI_DMA_BIDIRECTIONAL); | ||
164 | } | 168 | } |
169 | |||
165 | if (huge) { | 170 | if (huge) { |
166 | i = q->n_window; | 171 | i = q->n_window; |
167 | pci_unmap_single(priv->pci_dev, | 172 | pci_unmap_single(priv->pci_dev, |
@@ -169,6 +174,24 @@ void iwl_legacy_cmd_queue_free(struct iwl_priv *priv) | |||
169 | dma_unmap_len(&txq->meta[i], len), | 174 | dma_unmap_len(&txq->meta[i], len), |
170 | PCI_DMA_BIDIRECTIONAL); | 175 | PCI_DMA_BIDIRECTIONAL); |
171 | } | 176 | } |
177 | } | ||
178 | EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap); | ||
179 | |||
180 | /** | ||
181 | * iwl_legacy_cmd_queue_free - Deallocate DMA queue. | ||
182 | * @txq: Transmit queue to deallocate. | ||
183 | * | ||
184 | * Empty queue by removing and destroying all BD's. | ||
185 | * Free all buffers. | ||
186 | * 0-fill, but do not free "txq" descriptor structure. | ||
187 | */ | ||
188 | void iwl_legacy_cmd_queue_free(struct iwl_priv *priv) | ||
189 | { | ||
190 | struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; | ||
191 | struct device *dev = &priv->pci_dev->dev; | ||
192 | int i; | ||
193 | |||
194 | iwl_legacy_cmd_queue_unmap(priv); | ||
172 | 195 | ||
173 | /* De-alloc array of command/tx buffers */ | 196 | /* De-alloc array of command/tx buffers */ |
174 | for (i = 0; i <= TFD_CMD_SLOTS; i++) | 197 | for (i = 0; i <= TFD_CMD_SLOTS; i++) |