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)
*/
void iwl4965_txq_ctx_stop(struct iwl_priv *priv)
{
int ch;
int ch, txq_id;
unsigned long flags;
/* Turn off all Tx DMA fifos */
......@@ -719,6 +719,16 @@ void iwl4965_txq_ctx_stop(struct iwl_priv *priv)
FH_TSSR_TX_STATUS_REG));
}
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,
/*****************************************************
* RX
******************************************************/
void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv);
void iwl_legacy_cmd_queue_free(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,
......@@ -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,
struct iwl_tx_queue *txq,
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_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)
}
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.
* @txq: Transmit queue to deallocate.
......@@ -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)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct device *dev = &priv->pci_dev->dev;
int i;
if (q->n_bd == 0)
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);
iwl_legacy_tx_queue_unmap(priv, txq_id);
/* De-alloc array of command/tx buffers */
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)
EXPORT_SYMBOL(iwl_legacy_tx_queue_free);
/**
* 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.
* iwl_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue
*/
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_queue *q = &txq->q;
struct device *dev = &priv->pci_dev->dev;
int i;
bool huge = false;
int i;
if (q->n_bd == 0)
return;
for (; q->read_ptr != q->write_ptr;
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) {
while (q->read_ptr != q->write_ptr) {
/* we have no way to tell if it is a huge cmd ATM */
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;
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);
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
}
if (huge) {
i = q->n_window;
pci_unmap_single(priv->pci_dev,
......@@ -169,6 +174,24 @@ void iwl_legacy_cmd_queue_free(struct iwl_priv *priv)
dma_unmap_len(&txq->meta[i], len),
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 */
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