Commit 8a032c13 authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by John W. Linville

iwlegacy: fix dma mappings and skbs leak

Fix possible dma mappings and skbs introduced by commit
470058e0 "iwlwifi: avoid Tx queue
memory allocation in interface down".
Signed-off-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Acked-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 387f3381
...@@ -698,7 +698,7 @@ void iwl4965_txq_ctx_reset(struct iwl_priv *priv) ...@@ -698,7 +698,7 @@ void iwl4965_txq_ctx_reset(struct iwl_priv *priv)
*/ */
void iwl4965_txq_ctx_stop(struct iwl_priv *priv) void iwl4965_txq_ctx_stop(struct iwl_priv *priv)
{ {
int ch; int ch, txq_id;
unsigned long flags; unsigned long flags;
/* Turn off all Tx DMA fifos */ /* Turn off all Tx DMA fifos */
...@@ -719,6 +719,16 @@ void iwl4965_txq_ctx_stop(struct iwl_priv *priv) ...@@ -719,6 +719,16 @@ void iwl4965_txq_ctx_stop(struct iwl_priv *priv)
FH_TSSR_TX_STATUS_REG)); FH_TSSR_TX_STATUS_REG));
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
if (!priv->txq)
return;
/* Unmap DMA from host system and free skb's */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (txq_id == priv->cmd_queue)
iwl_legacy_cmd_queue_unmap(priv);
else
iwl_legacy_tx_queue_unmap(priv, txq_id);
} }
/* /*
......
...@@ -388,6 +388,7 @@ void iwl_legacy_rx_reply_error(struct iwl_priv *priv, ...@@ -388,6 +388,7 @@ void iwl_legacy_rx_reply_error(struct iwl_priv *priv,
/***************************************************** /*****************************************************
* RX * RX
******************************************************/ ******************************************************/
void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv);
void iwl_legacy_cmd_queue_free(struct iwl_priv *priv); void iwl_legacy_cmd_queue_free(struct iwl_priv *priv);
int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv); int iwl_legacy_rx_queue_alloc(struct iwl_priv *priv);
void iwl_legacy_rx_queue_update_write_ptr(struct iwl_priv *priv, 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,6 +416,7 @@ int iwl_legacy_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
void iwl_legacy_tx_queue_reset(struct iwl_priv *priv, void iwl_legacy_tx_queue_reset(struct iwl_priv *priv,
struct iwl_tx_queue *txq, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id); int slots_num, u32 txq_id);
void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id); void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id);
void iwl_legacy_setup_watchdog(struct iwl_priv *priv); void iwl_legacy_setup_watchdog(struct iwl_priv *priv);
/***************************************************** /*****************************************************
......
...@@ -81,6 +81,24 @@ iwl_legacy_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) ...@@ -81,6 +81,24 @@ iwl_legacy_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
} }
EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr); EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr);
/**
* iwl_legacy_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's
*/
void iwl_legacy_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
if (q->n_bd == 0)
return;
while (q->write_ptr != q->read_ptr) {
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
}
}
EXPORT_SYMBOL(iwl_legacy_tx_queue_unmap);
/** /**
* iwl_legacy_tx_queue_free - Deallocate DMA queue. * iwl_legacy_tx_queue_free - Deallocate DMA queue.
* @txq: Transmit queue to deallocate. * @txq: Transmit queue to deallocate.
...@@ -92,17 +110,10 @@ EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr); ...@@ -92,17 +110,10 @@ EXPORT_SYMBOL(iwl_legacy_txq_update_write_ptr);
void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id) void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id)
{ {
struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct device *dev = &priv->pci_dev->dev; struct device *dev = &priv->pci_dev->dev;
int i; int i;
if (q->n_bd == 0) iwl_legacy_tx_queue_unmap(priv, txq_id);
return;
/* first, empty all BD's */
for (; q->write_ptr != q->read_ptr;
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd))
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
for (i = 0; i < TFD_TX_CMD_SLOTS; i++) 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,39 +140,33 @@ void iwl_legacy_tx_queue_free(struct iwl_priv *priv, int txq_id)
EXPORT_SYMBOL(iwl_legacy_tx_queue_free); EXPORT_SYMBOL(iwl_legacy_tx_queue_free);
/** /**
* iwl_legacy_cmd_queue_free - Deallocate DMA queue. * iwl_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue
* @txq: Transmit queue to deallocate.
*
* Empty queue by removing and destroying all BD's.
* Free all buffers.
* 0-fill, but do not free "txq" descriptor structure.
*/ */
void iwl_legacy_cmd_queue_free(struct iwl_priv *priv) void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv)
{ {
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
struct iwl_queue *q = &txq->q; struct iwl_queue *q = &txq->q;
struct device *dev = &priv->pci_dev->dev;
int i;
bool huge = false; bool huge = false;
int i;
if (q->n_bd == 0) if (q->n_bd == 0)
return; return;
for (; q->read_ptr != q->write_ptr; while (q->read_ptr != q->write_ptr) {
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) {
/* we have no way to tell if it is a huge cmd ATM */ /* we have no way to tell if it is a huge cmd ATM */
i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0);
if (txq->meta[i].flags & CMD_SIZE_HUGE) { if (txq->meta[i].flags & CMD_SIZE_HUGE)
huge = true; huge = true;
continue; else
} pci_unmap_single(priv->pci_dev,
dma_unmap_addr(&txq->meta[i], mapping),
dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
pci_unmap_single(priv->pci_dev, q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
dma_unmap_addr(&txq->meta[i], mapping),
dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
} }
if (huge) { if (huge) {
i = q->n_window; i = q->n_window;
pci_unmap_single(priv->pci_dev, pci_unmap_single(priv->pci_dev,
...@@ -169,6 +174,24 @@ void iwl_legacy_cmd_queue_free(struct iwl_priv *priv) ...@@ -169,6 +174,24 @@ void iwl_legacy_cmd_queue_free(struct iwl_priv *priv)
dma_unmap_len(&txq->meta[i], len), dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL); PCI_DMA_BIDIRECTIONAL);
} }
}
EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap);
/**
* iwl_legacy_cmd_queue_free - Deallocate DMA queue.
* @txq: Transmit queue to deallocate.
*
* Empty queue by removing and destroying all BD's.
* Free all buffers.
* 0-fill, but do not free "txq" descriptor structure.
*/
void iwl_legacy_cmd_queue_free(struct iwl_priv *priv)
{
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
struct device *dev = &priv->pci_dev->dev;
int i;
iwl_legacy_cmd_queue_unmap(priv);
/* De-alloc array of command/tx buffers */ /* De-alloc array of command/tx buffers */
for (i = 0; i <= TFD_CMD_SLOTS; i++) for (i = 0; i <= TFD_CMD_SLOTS; i++)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment