Skip to content

Commit

Permalink
iwlagn: add an API to free the TX context
Browse files Browse the repository at this point in the history
Tx free functions move to the transport layer. Unify the functions that deal with tx queues and cmd queue.

Since the CMD queue is not fully allocated, but uses the q->n_bd / q->window trick, the release flow of TX queue and CMD queue was different.
iwlagn_txq_free_tfd receives now the index of the TFD to be freed, which allows to unify the release flow for all the queues.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Emmanuel Grumbach authored and John W. Linville committed Jul 11, 2011
1 parent afaf6b5 commit 1359ca4
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 148 deletions.
32 changes: 2 additions & 30 deletions drivers/net/wireless/iwlwifi/iwl-agn-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -851,31 +851,6 @@ static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
memset(ptr, 0, sizeof(*ptr));
}

/**
* iwlagn_hw_txq_ctx_free - Free TXQ Context
*
* Destroy all TX DMA queues and structures
*/
void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
{
int txq_id;

/* Tx queues */
if (priv->txq) {
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (txq_id == priv->cmd_queue)
iwl_cmd_queue_free(priv);
else
iwl_tx_queue_free(priv, txq_id);
}
iwlagn_free_dma_ptr(priv, &priv->kw);

iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);

/* free tx queue structure */
iwl_free_txq_mem(priv);
}

/**
* iwlagn_txq_ctx_stop - Stop all Tx DMA channels
*/
Expand Down Expand Up @@ -906,10 +881,7 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)

/* 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_cmd_queue_unmap(priv);
else
iwl_tx_queue_unmap(priv, txq_id);
iwl_tx_queue_unmap(priv, txq_id);
}

/*
Expand Down Expand Up @@ -1170,7 +1142,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)

iwlagn_txq_inval_byte_cnt_tbl(priv, txq);

iwlagn_txq_free_tfd(priv, txq);
iwlagn_txq_free_tfd(priv, txq, txq->q.read_ptr);
}
return nfreed;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/iwlwifi/iwl-agn.c
Original file line number Diff line number Diff line change
Expand Up @@ -3710,7 +3710,7 @@ void __devexit iwl_remove(struct iwl_priv * priv)
iwl_dealloc_ucode(priv);

priv->trans.ops->rx_free(priv);
iwlagn_hw_txq_ctx_free(priv);
priv->trans.ops->tx_free(priv);

iwl_eeprom_free(priv);

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/iwlwifi/iwl-agn.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
void iwl_setup_rx_handlers(struct iwl_priv *priv);

/* tx */
void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int index);
int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
dma_addr_t addr, u16 len, u8 reset);
Expand All @@ -217,7 +218,6 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
void iwlagn_txq_ctx_stop(struct iwl_priv *priv);

static inline u32 iwl_tx_status_to_mac80211(u32 status)
Expand Down
6 changes: 0 additions & 6 deletions drivers/net/wireless/iwlwifi/iwl-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1370,12 +1370,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,

}

void iwl_free_txq_mem(struct iwl_priv *priv)
{
kfree(priv->txq);
priv->txq = NULL;
}

#ifdef CONFIG_IWLWIFI_DEBUGFS

#define IWL_TRAFFIC_DUMP_SIZE (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
Expand Down
5 changes: 0 additions & 5 deletions drivers/net/wireless/iwlwifi/iwl-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
int iwl_mac_change_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
void iwl_free_txq_mem(struct iwl_priv *priv);

#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_alloc_traffic_mem(struct iwl_priv *priv);
void iwl_free_traffic_mem(struct iwl_priv *priv);
Expand Down Expand Up @@ -371,8 +369,6 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
/*****************************************************
* RX
******************************************************/
void iwl_cmd_queue_free(struct iwl_priv *priv);
void iwl_cmd_queue_unmap(struct iwl_priv *priv);
void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
Expand All @@ -386,7 +382,6 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
* TX
******************************************************/
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
int count, int slots_num, u32 id);
void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id);
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/iwlwifi/iwl-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -1233,11 +1233,14 @@ struct iwl_trans;
* @rx_init: inits the rx memory, allocate it if needed
* @rx_free: frees the rx memory
* @tx_init:inits the tx memory, allocate if needed
* @tx_free: frees the tx memory
*/
struct iwl_trans_ops {
int (*rx_init)(struct iwl_priv *priv);
void (*rx_free)(struct iwl_priv *priv);

int (*tx_init)(struct iwl_priv *priv);
void (*tx_free)(struct iwl_priv *priv);
};

struct iwl_trans {
Expand Down
83 changes: 81 additions & 2 deletions drivers/net/wireless/iwlwifi/iwl-trans.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,16 @@ static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
return 0;
}

static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
struct iwl_dma_ptr *ptr)
{
if (unlikely(!ptr->addr))
return;

dma_free_coherent(priv->bus.dev, ptr->size, ptr->addr, ptr->dma);
memset(ptr, 0, sizeof(*ptr));
}

static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id)
{
Expand All @@ -212,6 +222,8 @@ static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq,
if (WARN_ON(txq->meta || txq->cmd || txq->txb || txq->tfds))
return -EINVAL;

txq->q.n_window = slots_num;

txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num,
GFP_KERNEL);
txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num,
Expand Down Expand Up @@ -306,6 +318,72 @@ static int iwl_trans_txq_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
return 0;
}

/**
* iwl_tx_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.
*/
static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct device *dev = priv->bus.dev;
int i;
if (WARN_ON(!txq))
return;

iwl_tx_queue_unmap(priv, txq_id);

/* De-alloc array of command/tx buffers */
for (i = 0; i < txq->q.n_window; i++)
kfree(txq->cmd[i]);

/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd) {
dma_free_coherent(dev, priv->hw_params.tfd_size *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
}

/* De-alloc array of per-TFD driver data */
kfree(txq->txb);
txq->txb = NULL;

/* deallocate arrays */
kfree(txq->cmd);
kfree(txq->meta);
txq->cmd = NULL;
txq->meta = NULL;

/* 0-fill queue descriptor structure */
memset(txq, 0, sizeof(*txq));
}

/**
* iwl_trans_tx_free - Free TXQ Context
*
* Destroy all TX DMA queues and structures
*/
static void iwl_trans_tx_free(struct iwl_priv *priv)
{
int txq_id;

/* Tx queues */
if (priv->txq) {
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
iwl_tx_queue_free(priv, txq_id);
}

kfree(priv->txq);
priv->txq = NULL;

iwlagn_free_dma_ptr(priv, &priv->kw);

iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
}

/**
* iwl_trans_tx_alloc - allocate TX context
* Allocate all Tx DMA structures and initialize them
Expand Down Expand Up @@ -362,7 +440,7 @@ static int iwl_trans_tx_alloc(struct iwl_priv *priv)
return 0;

error:
iwlagn_hw_txq_ctx_free(priv);
priv->trans.ops->tx_free(priv);

return ret;
}
Expand Down Expand Up @@ -406,7 +484,7 @@ static int iwl_trans_tx_init(struct iwl_priv *priv)
error:
/*Upon error, free only if we allocated something */
if (alloc)
iwlagn_hw_txq_ctx_free(priv);
priv->trans.ops->tx_free(priv);
return ret;
}

Expand All @@ -415,6 +493,7 @@ static const struct iwl_trans_ops trans_ops = {
.rx_free = iwl_trans_rx_free,

.tx_init = iwl_trans_tx_init,
.tx_free = iwl_trans_tx_free,
};

void iwl_trans_register(struct iwl_trans *trans)
Expand Down
Loading

0 comments on commit 1359ca4

Please sign in to comment.