iwlagn: add an API to free the TX context
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Fri, 8 Jul 2011 15:46:10 +0000 (08:46 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 11 Jul 2011 19:02:00 +0000 (15:02 -0400)
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>
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-trans.c
drivers/net/wireless/iwlwifi/iwl-tx.c

index a87e95728b1df5582db1b2c4fb154f224308ad27..c90c78a081dd37f5a7c87778897d3e7ce2f81310 100644 (file)
@@ -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
  */
@@ -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);
 }
 
 /*
@@ -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;
 }
index 7e6c463abbdff3bdbf658a894045def6c2166a61..4d5b7cc33946320e08a51a48893616c8facc277f 100644 (file)
@@ -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);
 
index 4351151e2a913fdc17abc3afbd8727299f84dc5d..fabab0ff557795cde68fc4c6fe3694120dcfc280 100644 (file)
@@ -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);
@@ -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)
index f91e306c2498965652c155cb5b03d534aa06785f..9bf46864f0d12cfee5a8a0146145835403ce530b 100644 (file)
@@ -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)
index 6c21de9f5b60dd4edaac5bf5fc81b7abfd6039a1..7d8be6b26acd18d40adce3849767aa62fdc93a56 100644 (file)
@@ -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);
@@ -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);
@@ -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);
index e429e32f748ed06376213a369e3714d1060720c3..a29fdd43a9f3449d72f81a0e423e61ef28d72210 100644 (file)
@@ -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 {
index 7b7b97d8c2e1bdbda6d1b9234257def9a51e4a2c..38b43e41d5613d3fcbaa78cb7cb7f7871d31bd11 100644 (file)
@@ -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)
 {
@@ -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,
@@ -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
@@ -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;
 }
@@ -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;
 }
 
@@ -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)
index dc8f63f81cfaac49c79ebbd215483e517752e067..36b643a385be123dd9c543dd19095f03f1deb6db 100644 (file)
@@ -157,14 +157,15 @@ static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
  * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
  * @priv - driver private data
  * @txq - tx queue
+ * @index - the index of the TFD to be freed
  *
  * Does NOT advance any TFD circular buffer read/write indexes
  * Does NOT free the TFD itself (which is within circular buffer)
  */
-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)
 {
        struct iwl_tfd *tfd_tmp = txq->tfds;
-       int index = txq->q.read_ptr;
 
        iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index],
                         DMA_TO_DEVICE);
@@ -173,12 +174,12 @@ void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
        if (txq->txb) {
                struct sk_buff *skb;
 
-               skb = txq->txb[txq->q.read_ptr].skb;
+               skb = txq->txb[index].skb;
 
                /* can be called from irqs-disabled context */
                if (skb) {
                        dev_kfree_skb_any(skb);
-                       txq->txb[txq->q.read_ptr].skb = NULL;
+                       txq->txb[index].skb = NULL;
                }
        }
 }
@@ -232,108 +233,11 @@ void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
                return;
 
         while (q->write_ptr != q->read_ptr) {
-               iwlagn_txq_free_tfd(priv, txq);
+               iwlagn_txq_free_tfd(priv, txq, get_cmd_index(q, q->read_ptr));
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
 }
 
-/**
- * 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.
- */
-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;
-
-       iwl_tx_queue_unmap(priv, txq_id);
-
-       /* De-alloc array of command/tx buffers */
-       for (i = 0; i < TFD_TX_CMD_SLOTS; 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);
-
-       /* 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_cmd_queue_unmap - Unmap any remaining DMA mappings from command queue
- */
-void iwl_cmd_queue_unmap(struct iwl_priv *priv)
-{
-       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
-       struct iwl_queue *q = &txq->q;
-       int i;
-
-       if (q->n_bd == 0)
-               return;
-
-       while (q->read_ptr != q->write_ptr) {
-               i = get_cmd_index(q, q->read_ptr);
-
-               iwlagn_unmap_tfd(priv, &txq->meta[i], &txq->tfds[i],
-                                DMA_BIDIRECTIONAL);
-               txq->meta[i].flags = 0;
-
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-       }
-}
-
-/**
- * iwl_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_cmd_queue_free(struct iwl_priv *priv)
-{
-       struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
-       struct device *dev = priv->bus.dev;
-       int i;
-
-       iwl_cmd_queue_unmap(priv);
-
-       /* De-alloc array of command/tx buffers */
-       for (i = 0; i < TFD_CMD_SLOTS; 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);
-
-       /* deallocate arrays */
-       kfree(txq->cmd);
-       kfree(txq->meta);
-       txq->cmd = NULL;
-       txq->meta = NULL;
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
 /*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
  * DMA services
  *