aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2011-02-28 08:33:14 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-28 14:06:56 -0500
commit8a032c132b7ca011813df7c441b4a6fc89e5baee (patch)
tree5d716fbbd4c232c469da47e109752c8ee52bb57e /drivers
parent387f3381f732d8fa1b62213ae3276f2ae712dbe2 (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.c12
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-core.h2
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-tx.c75
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 */
699void iwl4965_txq_ctx_stop(struct iwl_priv *priv) 699void 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******************************************************/
391void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv);
391void iwl_legacy_cmd_queue_free(struct iwl_priv *priv); 392void iwl_legacy_cmd_queue_free(struct iwl_priv *priv);
392int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv); 393int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv);
393void iwl_legacy_rx_queue_update_write_ptr(struct iwl_priv *priv, 394void 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,
415void iwl_legacy_tx_queue_reset(struct iwl_priv *priv, 416void 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);
419void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
418void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id); 420void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id);
419void iwl_legacy_setup_watchdog(struct iwl_priv *priv); 421void 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)
82EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr); 82EXPORT_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 */
87void 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}
100EXPORT_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);
92void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id) 110void 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)
129EXPORT_SYMBOL(iwl_legacy_tx_queue_free); 140EXPORT_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 */
139void iwl_legacy_cmd_queue_free(struct iwl_priv *priv) 145void 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}
178EXPORT_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 */
188void 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++)