iwlwifi: reduce memory allocation
authorJohannes Berg <johannes.berg@intel.com>
Mon, 17 May 2010 09:37:34 +0000 (02:37 -0700)
committerReinette Chatre <reinette.chatre@intel.com>
Sun, 6 Jun 2010 06:18:33 +0000 (23:18 -0700)
Currently, the driver allocates up to 19 skb pointers
for each TFD, of which we have 256 per queue. This
means that for each TX queue, we allocate 19k/38k
(an order 4 or 5 allocation on 32/64 bit respectively)
just for each queue's "txb" array, which contains only
the SKB pointers.

However, due to the way we use these pointers only the
first one can ever be assigned. When the driver was
initially written, the idea was that it could be
passed multiple SKBs for each TFD and attach all
those to implement gather DMA. However, due to
constraints in the userspace API and lack of TCP/IP
level checksumming in the device, this is in fact not
possible. And even if it were, the SKBs would be
chained, and we wouldn't need to keep pointers to
each anyway.

Change this to only keep track of one SKB per TFD,
and thereby reduce memory consumption to just one
pointer per TFD, which is an order 0 allocation per
transmit queue.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl3945-base.c

index fec05b5c334e4e1c1cd7960e986120ba0dd320db..658c6143f998303bbb8dee51bbee64d9ccc22b9b 100644 (file)
@@ -279,8 +279,8 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
-               tx_info->skb[0] = NULL;
+               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
+               tx_info->skb = NULL;
                priv->cfg->ops->lib->txq_free_tfd(priv, txq);
        }
 
@@ -315,7 +315,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
                return;
        }
 
-       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
        ieee80211_tx_info_clear_status(info);
 
        /* Fill the MRR chain with some info about on-chip retransmissions */
@@ -702,19 +702,20 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 
        /* unmap chunks if any */
 
-       for (i = 1; i < counter; i++) {
+       for (i = 1; i < counter; i++)
                pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr),
                         le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE);
-               if (txq->txb) {
-                       struct sk_buff *skb;
 
-                       skb = txq->txb[txq->q.read_ptr].skb[i - 1];
+       /* free SKB */
+       if (txq->txb) {
+               struct sk_buff *skb;
 
-                       /* can be called from irqs-disabled context */
-                       if (skb) {
-                               dev_kfree_skb_any(skb);
-                               txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
-                       }
+               skb = txq->txb[txq->q.read_ptr].skb;
+
+               /* can be called from irqs-disabled context */
+               if (skb) {
+                       dev_kfree_skb_any(skb);
+                       txq->txb[txq->q.read_ptr].skb = NULL;
                }
        }
 }
index 1e4f1bc515dbfa6bbb6c6c1ac8f86409cfba3cbd..a51c4b8e65c770c9fe8fda79054cbda43ae2fcfe 100644 (file)
@@ -1908,7 +1908,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
                IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
                                   agg->frame_count, agg->start_idx, idx);
 
-               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                info->flags |= iwl_tx_status_to_mac80211(status);
@@ -2074,7 +2074,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                return;
        }
 
-       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
        memset(&info->status, 0, sizeof(info->status));
 
        hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
index 848cb3bb5c714e87dfe7c0a0a5bbba45c10213b7..5bec72a91fd726e8e394030253aac3bdd1a9e3f6 100644 (file)
@@ -77,7 +77,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
                IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
                                   agg->frame_count, agg->start_idx, idx);
 
-               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                info->flags |= iwl_tx_status_to_mac80211(status);
@@ -194,7 +194,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
                return;
        }
 
-       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
        memset(&info->status, 0, sizeof(info->status));
 
        tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
index eb0a6da76cbbdd40d718b35a6c440d5b55595f7a..0037a52f2e377df97fe0f127d8a4929cb56b2c72 100644 (file)
@@ -638,7 +638,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
-       txq->txb[q->write_ptr].skb[0] = skb;
+       txq->txb[q->write_ptr].skb = skb;
 
        /* Set up first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[q->write_ptr];
@@ -1178,12 +1178,12 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info->skb[0]);
+               iwlagn_tx_status(priv, tx_info->skb);
 
-               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               hdr = (struct ieee80211_hdr *)tx_info->skb->data;
                if (hdr && ieee80211_is_data_qos(hdr->frame_control))
                        nfreed++;
-               tx_info->skb[0] = NULL;
+               tx_info->skb = NULL;
 
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
                        priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
@@ -1247,7 +1247,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
                        agg->start_idx + i);
        }
 
-       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
        memset(&info->status, 0, sizeof(info->status));
        info->flags |= IEEE80211_TX_STAT_ACK;
        info->flags |= IEEE80211_TX_STAT_AMPDU;
index a61d5674d13e90b82f8e4e2704eb035867aa96bd..a0e995ec453af91dae23a32f04169fc4ab51cc1d 100644 (file)
@@ -479,20 +479,20 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
                                PCI_DMA_BIDIRECTIONAL);
 
        /* Unmap chunks, if any. */
-       for (i = 1; i < num_tbs; i++) {
+       for (i = 1; i < num_tbs; i++)
                pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
                                iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
 
-               if (txq->txb) {
-                       struct sk_buff *skb;
+       /* free SKB */
+       if (txq->txb) {
+               struct sk_buff *skb;
 
-                       skb = txq->txb[txq->q.read_ptr].skb[i - 1];
+               skb = txq->txb[txq->q.read_ptr].skb;
 
-                       /* can be called from irqs-disabled context */
-                       if (skb) {
-                               dev_kfree_skb_any(skb);
-                               txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
-                       }
+               /* can be called from irqs-disabled context */
+               if (skb) {
+                       dev_kfree_skb_any(skb);
+                       txq->txb[txq->q.read_ptr].skb = NULL;
                }
        }
 }
index 4abc24ef64a5c266047e72a47be650903290e60d..de326a6f25e7d194840725edc5f49b6fccbc4e0f 100644 (file)
@@ -142,7 +142,7 @@ struct iwl_queue {
 
 /* One for each TFD */
 struct iwl_tx_info {
-       struct sk_buff *skb[IWL_NUM_OF_TBS - 1];
+       struct sk_buff *skb;
 };
 
 /**
@@ -1425,9 +1425,9 @@ static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
 static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
                                                         int txq_id, int idx)
 {
-       if (priv->txq[txq_id].txb[idx].skb[0])
+       if (priv->txq[txq_id].txb[idx].skb)
                return (struct ieee80211_hdr *)priv->txq[txq_id].
-                               txb[idx].skb[0]->data;
+                               txb[idx].skb->data;
        return NULL;
 }
 
index eeeb6e8cd1de008c9cd73d770802227de3b80d6b..c3e9d633194a683a54f502268a6fadaeeaa81165 100644 (file)
@@ -538,7 +538,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
-       txq->txb[q->write_ptr].skb[0] = skb;
+       txq->txb[q->write_ptr].skb = skb;
 
        /* Init first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = txq->cmd[idx];