aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-05-17 05:37:34 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-06-06 02:18:33 -0400
commitff0d91c3eea6e25b47258349b455671f98f1b0cd (patch)
treecc69b1e6603db5c36e6026518882dd1b458c2327
parent519c7c416870c6e71e9553786a529d89f55ef395 (diff)
iwlwifi: reduce memory allocation
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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c2
7 files changed, 35 insertions, 34 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index fec05b5c334e..658c6143f998 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -279,8 +279,8 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
279 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { 279 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
280 280
281 tx_info = &txq->txb[txq->q.read_ptr]; 281 tx_info = &txq->txb[txq->q.read_ptr];
282 ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); 282 ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
283 tx_info->skb[0] = NULL; 283 tx_info->skb = NULL;
284 priv->cfg->ops->lib->txq_free_tfd(priv, txq); 284 priv->cfg->ops->lib->txq_free_tfd(priv, txq);
285 } 285 }
286 286
@@ -315,7 +315,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
315 return; 315 return;
316 } 316 }
317 317
318 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); 318 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
319 ieee80211_tx_info_clear_status(info); 319 ieee80211_tx_info_clear_status(info);
320 320
321 /* Fill the MRR chain with some info about on-chip retransmissions */ 321 /* 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)
702 702
703 /* unmap chunks if any */ 703 /* unmap chunks if any */
704 704
705 for (i = 1; i < counter; i++) { 705 for (i = 1; i < counter; i++)
706 pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr), 706 pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr),
707 le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE); 707 le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE);
708 if (txq->txb) {
709 struct sk_buff *skb;
710 708
711 skb = txq->txb[txq->q.read_ptr].skb[i - 1]; 709 /* free SKB */
710 if (txq->txb) {
711 struct sk_buff *skb;
712 712
713 /* can be called from irqs-disabled context */ 713 skb = txq->txb[txq->q.read_ptr].skb;
714 if (skb) { 714
715 dev_kfree_skb_any(skb); 715 /* can be called from irqs-disabled context */
716 txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; 716 if (skb) {
717 } 717 dev_kfree_skb_any(skb);
718 txq->txb[txq->q.read_ptr].skb = NULL;
718 } 719 }
719 } 720 }
720} 721}
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 1e4f1bc515db..a51c4b8e65c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -1908,7 +1908,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
1908 IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", 1908 IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
1909 agg->frame_count, agg->start_idx, idx); 1909 agg->frame_count, agg->start_idx, idx);
1910 1910
1911 info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); 1911 info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
1912 info->status.rates[0].count = tx_resp->failure_frame + 1; 1912 info->status.rates[0].count = tx_resp->failure_frame + 1;
1913 info->flags &= ~IEEE80211_TX_CTL_AMPDU; 1913 info->flags &= ~IEEE80211_TX_CTL_AMPDU;
1914 info->flags |= iwl_tx_status_to_mac80211(status); 1914 info->flags |= iwl_tx_status_to_mac80211(status);
@@ -2074,7 +2074,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
2074 return; 2074 return;
2075 } 2075 }
2076 2076
2077 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); 2077 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
2078 memset(&info->status, 0, sizeof(info->status)); 2078 memset(&info->status, 0, sizeof(info->status));
2079 2079
2080 hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); 2080 hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 848cb3bb5c71..5bec72a91fd7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -77,7 +77,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
77 IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", 77 IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
78 agg->frame_count, agg->start_idx, idx); 78 agg->frame_count, agg->start_idx, idx);
79 79
80 info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); 80 info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
81 info->status.rates[0].count = tx_resp->failure_frame + 1; 81 info->status.rates[0].count = tx_resp->failure_frame + 1;
82 info->flags &= ~IEEE80211_TX_CTL_AMPDU; 82 info->flags &= ~IEEE80211_TX_CTL_AMPDU;
83 info->flags |= iwl_tx_status_to_mac80211(status); 83 info->flags |= iwl_tx_status_to_mac80211(status);
@@ -194,7 +194,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
194 return; 194 return;
195 } 195 }
196 196
197 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); 197 info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
198 memset(&info->status, 0, sizeof(info->status)); 198 memset(&info->status, 0, sizeof(info->status));
199 199
200 tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; 200 tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index eb0a6da76cbb..0037a52f2e37 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -638,7 +638,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
638 638
639 /* Set up driver data for this TFD */ 639 /* Set up driver data for this TFD */
640 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); 640 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
641 txq->txb[q->write_ptr].skb[0] = skb; 641 txq->txb[q->write_ptr].skb = skb;
642 642
643 /* Set up first empty entry in queue's array of Tx/cmd buffers */ 643 /* Set up first empty entry in queue's array of Tx/cmd buffers */
644 out_cmd = txq->cmd[q->write_ptr]; 644 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)
1178 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { 1178 q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
1179 1179
1180 tx_info = &txq->txb[txq->q.read_ptr]; 1180 tx_info = &txq->txb[txq->q.read_ptr];
1181 iwlagn_tx_status(priv, tx_info->skb[0]); 1181 iwlagn_tx_status(priv, tx_info->skb);
1182 1182
1183 hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data; 1183 hdr = (struct ieee80211_hdr *)tx_info->skb->data;
1184 if (hdr && ieee80211_is_data_qos(hdr->frame_control)) 1184 if (hdr && ieee80211_is_data_qos(hdr->frame_control))
1185 nfreed++; 1185 nfreed++;
1186 tx_info->skb[0] = NULL; 1186 tx_info->skb = NULL;
1187 1187
1188 if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) 1188 if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
1189 priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); 1189 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,
1247 agg->start_idx + i); 1247 agg->start_idx + i);
1248 } 1248 }
1249 1249
1250 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); 1250 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
1251 memset(&info->status, 0, sizeof(info->status)); 1251 memset(&info->status, 0, sizeof(info->status));
1252 info->flags |= IEEE80211_TX_STAT_ACK; 1252 info->flags |= IEEE80211_TX_STAT_ACK;
1253 info->flags |= IEEE80211_TX_STAT_AMPDU; 1253 info->flags |= IEEE80211_TX_STAT_AMPDU;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index a61d5674d13e..a0e995ec453a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -479,20 +479,20 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
479 PCI_DMA_BIDIRECTIONAL); 479 PCI_DMA_BIDIRECTIONAL);
480 480
481 /* Unmap chunks, if any. */ 481 /* Unmap chunks, if any. */
482 for (i = 1; i < num_tbs; i++) { 482 for (i = 1; i < num_tbs; i++)
483 pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), 483 pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
484 iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); 484 iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
485 485
486 if (txq->txb) { 486 /* free SKB */
487 struct sk_buff *skb; 487 if (txq->txb) {
488 struct sk_buff *skb;
488 489
489 skb = txq->txb[txq->q.read_ptr].skb[i - 1]; 490 skb = txq->txb[txq->q.read_ptr].skb;
490 491
491 /* can be called from irqs-disabled context */ 492 /* can be called from irqs-disabled context */
492 if (skb) { 493 if (skb) {
493 dev_kfree_skb_any(skb); 494 dev_kfree_skb_any(skb);
494 txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; 495 txq->txb[txq->q.read_ptr].skb = NULL;
495 }
496 } 496 }
497 } 497 }
498} 498}
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 4abc24ef64a5..de326a6f25e7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -142,7 +142,7 @@ struct iwl_queue {
142 142
143/* One for each TFD */ 143/* One for each TFD */
144struct iwl_tx_info { 144struct iwl_tx_info {
145 struct sk_buff *skb[IWL_NUM_OF_TBS - 1]; 145 struct sk_buff *skb;
146}; 146};
147 147
148/** 148/**
@@ -1425,9 +1425,9 @@ static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
1425static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv, 1425static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
1426 int txq_id, int idx) 1426 int txq_id, int idx)
1427{ 1427{
1428 if (priv->txq[txq_id].txb[idx].skb[0]) 1428 if (priv->txq[txq_id].txb[idx].skb)
1429 return (struct ieee80211_hdr *)priv->txq[txq_id]. 1429 return (struct ieee80211_hdr *)priv->txq[txq_id].
1430 txb[idx].skb[0]->data; 1430 txb[idx].skb->data;
1431 return NULL; 1431 return NULL;
1432} 1432}
1433 1433
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index eeeb6e8cd1de..c3e9d633194a 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -538,7 +538,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
538 538
539 /* Set up driver data for this TFD */ 539 /* Set up driver data for this TFD */
540 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); 540 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
541 txq->txb[q->write_ptr].skb[0] = skb; 541 txq->txb[q->write_ptr].skb = skb;
542 542
543 /* Init first empty entry in queue's array of Tx/cmd buffers */ 543 /* Init first empty entry in queue's array of Tx/cmd buffers */
544 out_cmd = txq->cmd[idx]; 544 out_cmd = txq->cmd[idx];